Adler32 生成的校验和与 .txt 文件校验和不匹配

Adler32 generated checksum doesnt match the .txt files checksum

我的任务是编写两个 java 程序。一个程序创建一个名为 'userinput.txt' 的文件,然后将用户输入的所有内容写入该文件。完成后,将创建一个名为 'Checksum.txt' 的新文件,该文件将在读取其中的内容后记下 'userinput.txt' 文件的校验和。

第二个程序只读取相同的 'userinput.txt' 文件,然后生成校验和并将其打印到控制台(我还必须让程序读取另一个 checksum.txt 文件并显示它在控制台中比较两者,但我还没有解决这个问题)。

我为这两个程序编写了程序,但我的问题是它们的校验和不同,即使它们读取的是同一个文件。我使用的是 Adler32,但 CRC32 也给了我两个不同的校验和(控制台上的校验和总是与 checksum.txt 中存储的校验和不同),坦率地说,我不确定是什么原因造成的:/

这是接受用户输入并生成校验和文件的代码:

package attemp2;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
import java.util.zip.Adler32;
import java.util.zip.CheckedInputStream;

public class main {
    public static void main(String[] args) throws IOException {
        System.out.println("All inputs will be recorded into a sigle file. Enter 'x' when done. A checksum File will aslo be created at the end");
        FileWriter fw = new FileWriter("d:/input.txt", false); // clears previous entry in file.
        while (true) {
            Scanner input = new Scanner(System.in); //get user input
            String ch = input.nextLine(); //stores user input
            System.out.println(ch); //prints out what user just inputed
            if (ch.equals("x")) { //stops running if 'x' is entered
                break;
            }
            BufferedWriter writer = new BufferedWriter(new FileWriter("d:/input.txt", true));
            writer.write(ch);
            writer.newLine(); // Add new line
            writer.close();
        }
        try {
            FileReader reader = new FileReader("d:/input.txt");
            BufferedReader br = new BufferedReader(reader);
            // read line by line String line;
            String read = "";
            String line;
            while ((line = br.readLine()) != null) {
                read = read + line;
                //prints out text in file currently
                System.out.println(line);
            }
            //checksum.txt generation
            byte buffer[] = read.getBytes();
            ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
            CheckedInputStream cis = new CheckedInputStream(bais, new Adler32());
            byte readBuffer[] = new byte[buffer.length];
            cis.read(readBuffer);
            FileOutputStream out = new FileOutputStream("d://checksum.txt");
            BufferedWriter wrt = new BufferedWriter(new FileWriter("d:/checksum.txt", false));
            wrt.write(Long.toString(cis.getChecksum().getValue()));
            wrt.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

读取文件并在控制台生成校验和的代码:

package check;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;
import java.util.zip.Adler32;

public class CheckSum {

   private Adler32 checksum;
   private String filepath;
   InputStream inputStream;

   public CheckSum(String filepath) throws FileNotFoundException{
       this.filepath = filepath;
       checksum = new Adler32();
       inputStream = new FileInputStream(filepath);
   }

   public long generateChecksum() throws IOException{

       int c;

       while((c = inputStream.read())!=-1){
           checksum.update(c);
       }

       return checksum.getValue();
   }

   public void read() throws IOException{
       File file = new File(filepath);

       BufferedReader br = new BufferedReader(new FileReader(file));

       String st;

       while ((st = br.readLine()) != null) {
       System.out.println(st);
       }
   }

   public static void main(String[] args) throws Exception{

       Scanner scanner = new Scanner(System.in);
       String filepath = "d:/input.txt";
       CheckSum checksum = new CheckSum(filepath);

       checksum.read();

       System.out.println("For the file: "+filepath);
       System.out.println("The checksum generated is: "+checksum.generateChecksum());


   }
}

请了解如何使用调试器,请参阅 What is a debugger and how can it help me diagnose problems?

话虽这么说,但您的代码存在一些问题。首先,您要计算一个空数组的校验和。当你写:

byte readBuffer[] = new byte[buffer.length];
cis.read(readBuffer);

您正在读取 buffer 数组大小的空数组。您不需要创建新数组。事实上,您应该阅读已有的 buffer 数组,因为那里有您的内容。在这种情况下,您只需写:

cis.read(buffer);

下一个问题是您正在使用读取器和写入器,它们用于 text/string 文件,但 checksum/hash 算法通常在字节级别上工作。这可能会导致一些错误,例如编码(ASCII、UTF-8 等)和行终止问题(\n vs. \r\n vs. \r)。

但是,在这种情况下,您使用的是 readLine()。此方法没有 return 最后的行终止,请参阅 the documentation of readLine():

Returns:

A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached

因此,您从文件中读取的内容与文件中实际 不同。但是您的 CheckSum class 读取已保存文件中的 每个字节 (应该如此)。假设您只输入字符串 "abc"。您的第一个计算将是 运行 在 3 字节长的数组上,其值为:

[97,98,99]

行终止被readLine() 方法忽略,但它仍然存在于文件中。当您使用第二个程序检查校验和时,您正在使用的 InputStream 将看到以下字节:

[97,98,99,10]

(最后的字节数取决于你使用的OS)

如您所见,运行 不同字节数组的校验和,导致不同的校验和值。因此,请确保您 运行 对相同的字节数组内容(或 InputStream 内容)进行校验和检查,以便在两个应用程序中获得相同的校验和。