首页 > 解决方案 > 在Java中将十六进制字符解码为ASCII时的奇怪行为

问题描述

我编写了一个 Java 程序来获取文件的行,并整理出一个特定的 id,然后将其从 HEX 转换为 ASCII 字符。对几个文件效果很好,直到它发现似乎是回车的“0D”十六进制字符(不知道那是做什么的)。

当它遇到这种情况时,它会结束行输出(它不应该这样做)。我无法弄清楚发生了什么。

这是代码,编译时没有错误。我附上了一张带有结果的图片。

文件 1 包含 ID=xxx:LENGHT=8 之前的字符,之后需要转换的 8 个 HEX 字符。之后,程序转换并添加同一行中的文本。我需要他们在同一条线上才能找出模式。

import java.io.*;
import java.util.Scanner;
import java.io.FileWriter;
import java.io.IOException;


public class FrameDecoder {

    public static void main(String[] args) throws IOException {
        try {
            // Sortam frameurile cu id-ul tinta

            File fisierSursa = new File("file1.txt"); //Fisierul original
            FileWriter fisierData = new FileWriter("file2.txt");  //Fisierul cu frameurile care au id-ul cautat
            FileWriter fisierTranzit = new FileWriter("file3.txt");  //Fisier cu caractere HEX, care va fi sters.

            Scanner citireSursa = new Scanner(fisierSursa);
            

            while (citireSursa.hasNextLine()){
                String data = citireSursa.nextLine();
                //System.out.println("data = " + data);
                int intIndex = data.indexOf("ID=289");  // idul pe care il cauti
                int intIndex2 = data.indexOf("ID=1313");  //al doilea id pe care il cauti


                if (intIndex != -1 || intIndex2 != -1){
                    char[] text = data.toCharArray();
                    int counter = 0;

                    for (int i=0; i<text.length; i++){
                        if (text[i] == ':' && counter < 5){
                            counter++;
                        }
                        if (text[i] == ':' && counter == 5){
                            fisierTranzit.write(text[i+1]);
                            fisierTranzit.write(text[i+2]);
                        }
                    }

                    fisierTranzit.write("\r\n");
                    fisierData.write(data + "\r\n");
                }
            }

            citireSursa.close();
            fisierTranzit.close();
            fisierData.close();

            // Convertire HEX to ASCII

            FileWriter fisierAscii = new FileWriter("file4.txt");  //Fisier care va contine caraterele ASCII decodate
            File fisierTranzitRedeschis = new File("file3.txt");  //Reinitializam fisierul tranzit pentru a putea citi din el
            Scanner citireTranzit = new Scanner(fisierTranzitRedeschis);



            while (citireTranzit.hasNextLine()){
                String data2 = citireTranzit.nextLine();
                System.out.println("data2 = " + data2);
                if (data2.length() % 2 != 0){
                    System.err.println("Invalid hex string!");
                    return;
                }


                StringBuilder builder = new StringBuilder();
                for (int i=0; i<data2.length(); i=i+2){
                    //Impartim sirul in grupe de cate doua caractere
                    String s = data2.substring(i, i+2);
                    //Convertim fiecare grup in integer folosinf valueOfTheMetod
                    int n = Integer.valueOf(s, 16);
                    //Convertim valoare integer in char
                    builder.append((char)n);
                }

                fisierAscii.write(builder.toString() + "\r\n");
                //System.out.println(builder.toString());

            }

            citireTranzit.close();
            fisierAscii.close();

            //Stergem fisierul 3

            File stergereFisier3 = new File("file3.txt");

            if(stergereFisier3.delete()){
                System.out.println("File 3 deleted successfully");
            }else{
                System.out.println("Failed to delete file 3");
            }


            // Combinam fisierele

            PrintWriter fisierFinal = new PrintWriter("file5.txt");

            BufferedReader br1 = new BufferedReader(new FileReader("file2.txt"));
            BufferedReader br2 = new BufferedReader(new FileReader("file4.txt"));

            String line1 = br1.readLine();
            String line2 = br2.readLine();

             //loop to copy lines
             //of file1.txt and file2.txt
             //to file3.txt alternatively

            while (line1 != null || line2 !=null){
                if(line1 != null){
                    fisierFinal.print(line1 + "  ");
                    line1 = br1.readLine();
                }

                if (line2 != null){
                    fisierFinal.println(line2 );
                    line2 = br2.readLine();
                }
            }

            fisierFinal.flush();

            //closing resources

            br1.close();
            br2.close();
            fisierFinal.close();

            System.out.println("Merged files succesfully");

            //Stergem fisierul 2 si 4

            File stergereFisier2 = new File("file2.txt");
            File stergereFisier4 = new File("file4.txt");

            if(stergereFisier2.delete() && stergereFisier4.delete()){
                System.out.println("Files 2 and 4 deleted successfully");
            }else{
                System.out.println("Failed to delete files 2 and 4");
            }


        }catch (FileNotFoundException e){
            System.out.println("An error occurred.");
            e.printStackTrace();
        }catch (IOException e){
            System.out.println("No data to print");
            e.printStackTrace();
        }

    }
}

编辑:我在打印 HEX 字符时作了一点小作弊,并设置了一个条件,如果遇到 0D,只需将它们替换为 00。它起作用了。我也试试你的方法,那个好像比我的好。

for (int i=0; i<text.length; i++){
                        if (text[i] == ':' && counter < 5){
                            counter++;
                        }
                        if (text[i] == ':' && counter == 5){
                            if(text[i+1] == '0' && text[i+2] == 'D'){
                                fisierTranzit.write('0');
                                fisierTranzit.write('0');
                            }
                            else{
                                fisierTranzit.write(text[i+1]);
                                fisierTranzit.write(text[i+2]);
                            }
                        }
                    }

标签: javahexcharacterascii

解决方案


回车符\r(十六进制0D)是标准行分隔符之一,Scanner.hasNextLine()并且nextLine()方法假定它必须终止当前行。

要获得更多控制,请将delimiterfor Scanner 设置为仅换行符\n并使用 hasNext/next 方法而不是 hasNextLine/nextLine 方法。例如:

Scanner citireTranzit = new Scanner(fisierTranzitRedeschis);
citireTranzit.useDelimiter("\n");

while (citireTranzit.hasNext()){
    String data2 = citireTranzit.next();
    ...
}

推荐阅读