14

我正在用 Java 编写一个程序,需要我比较 2 个文件中的数据。我必须检查文件 1 中的每一行与文件 2 的每一行,如果找到匹配项,则将它们写入第三个文件。读取到文件 2 的末尾后,如何将指针重置到文件的开头?

public class FiFo {
    public static void main(String[] args) 
    {
        FileReader file1=new FileReader("d:\\testfiles\\FILE1.txt");
        FileReader file2=new FileReader("d:\\testfiles\\FILE2.txt");
        try{
            String s1,s2;
            while((s1=file1.data.readLine())!=null){
                System.out.println("s1: "+s1);
                while((s2=file2.data.readLine())!=null){
                    System.out.println("s2: "+s2);
                }
            }
            file1.closeFile();
            file2.closeFile();
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class FileReader {
    BufferedReader data;
    DataInputStream in;

    public FileReader(String fileName)
    {
        try{
            FileInputStream fstream = new FileInputStream(fileName);
            data = new BufferedReader(new InputStreamReader(fstream));
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    } 

    public void closeFile()
    {
        try{
            in.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}
4

10 回答 10

15

我相信RandomAccessFile这是你需要的。它包含:RandomAccessFile#seekRandomAccessFile#getFilePointer

rewind()seek(0)

于 2010-02-09T04:27:18.237 回答
5

我认为最好的办法是将文件 1 中的每一行放入HashMap; 那么您可以检查文件 2 的每一行是否属于您的成员,HashMap而不是为文件 1 的每一行读取整个文件一次。

但是要回答您关于如何回到文件开头的问题,最简单的方法是打开另一个InputStream/ Reader

于 2010-02-09T04:22:43.177 回答
2

显然,您可以像这样关闭并重新打开文件:

     while((s1=file1.data.readLine())!=null){
         System.out.println("s1: "+s1);
         FileReader file2=new FileReader("d:\\testfiles\\FILE2.txt");
         while((s2=file2.data.readLine())!=null){
             System.out.println("s2: "+s2);
             //compare s1 and s2;
         }
         file2.closeFile()
     }

但是你真的不想那样做,因为这个算法的运行时间是 O(n 2 )。如果文件 A 中有 1000 行,文件 B 中有 10000 行,那么您的内部循环将运行 1,000,000 次。

您应该做的是读取每一行并将其存储在允许快速检查项目是否已包含(可能是 HashSet)的集合中。

如果您只需要检查文件 2 中的每一行是否在文件 1 中,那么您只需将文件 1 中的每一行添加到一个 HashSet 中,然后检查文件 2 中的每一行是否在该集合中。

如果您需要进行交叉比较,在其中找到每个字符串在一个字符串中但不在另一个字符串中,那么您将需要两个哈希集,每个文件一个。(虽然有一个技巧可以只使用一个)

如果文件太大以至于您没有足够的内存,那么您原来的 n 2方法无论如何都不会起作用。

于 2010-02-09T05:38:10.300 回答
1

正如其他人所建议的那样,您应该考虑解决问题的其他方法。对于返回到文件中的前一点的特定问题,java.io.FileReader似乎继承mark()reset()解决此目标的方法。不幸的是,markSupported()回报false

或者,确实支持. 下面的程序打印出来,说明效果。BufferedReader mark()true

package cli;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class FileReaderTest {

    public static void main(String[] args) {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(
                new FileInputStream("src/cli/FileReaderTest.java")));
            in.mark(1);
            int i1 = in.read(); in.read(); in.read();
            in.reset();
            int i2 = in.read();
            System.out.println(i1 == i2);
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}
于 2010-02-09T06:24:01.267 回答
1

好吧,Gennady S. 的答案是我用来解决您的问题的方法。

我正在用 Java 编写一个程序,需要我比较 2 个文件中的数据

但是,我宁愿不再编码。我宁愿使用类似http://code.google.com/p/java-diff-utils/

于 2010-02-09T05:13:29.127 回答
0

我相信您可以重新初始化文件 2 文件阅读器并且应该重置它。

于 2014-01-23T16:20:15.550 回答
0

如前所述,有更好的算法 - 研究这些

在旁边:

FileReader 没有实现mark 和reset,所以trashgod 的注释是不准确的。您要么必须实现这个版本(使用 RandomAccessFile 或其他),要么包装在 BufferedReader 中。但是,如果您标记它,后者会将整个内容加载到内存中

于 2010-03-19T19:51:02.453 回答
0

只是一个快速的问题。你不能让一个对象指向文件的开头并用另一个对象遍历文件吗?然后,当您到达末尾时,只需将其指向文件(流)开头的对象。我相信 C++ 有这样的文件 I/O 机制(或者它是流 I/O)

于 2010-03-19T20:04:06.553 回答
0

如果您只想将文件指针重置为文件顶部,请重新初始化缓冲区阅读器。我假设您也在使用 try 和 catch 块来检查文件的结尾。

`//To read from a file. 
      BufferedReader read_data_file = new BufferedReader(new FileReader("Datafile.dat"));'

假设这就是您定义缓冲区阅读器的方式。现在,这就是您检查文件结尾=null 的方法。

boolean has_data= true;

while(has_data)
     {    
      try
     {
     record = read_data_file.readLine();
     delimit = new StringTokenizer(record, ",");
     //Reading the input in STRING format. 
     cus_ID = delimit.nextToken();
     cus_name = delimit.nextToken();'
      //And keep grabbing the data and save it in appropriate fields. 
     }
catch (NullPointerException e)
     {
      System.out.println("\nEnd of Data File... Total "+ num_of_records 
                       + " records were printed. \n \n");
      has_data = false; //To exit the loop. 
      /*
        ------> This point is the trouble maker. Your file pointer is pointing at the end of the line. 
     -->If you want to again read all the data FROM THE TOP WITHOUT   RECOMPILING: 
      Do this--> Reset the buffer reader to the top of the file.
      */                      
      read_data_file = new BufferedReader(new FileReader(new File("datafile.dat")));
}

通过重新初始化缓冲区阅读器,您将文件阅读器标记/指针重置为文件的顶部,并且您不必重新编译文件以将文件阅读器标记/指针设置为文件的开头/顶部。仅当您不想在同一次运行中重新编译和完成相同的特技时,才需要重新初始化缓冲区读取器。但是,如果您希望只运行一次循环,那么您不必这样做,只需重新编译文件,文件阅读器标记将设置为文件的顶部/开头。

于 2016-07-28T06:06:25.433 回答
0

如果您可以清楚地识别文件的尺寸,则可以使用BufferedReader类中的mark(int readAheadLimit)reset()。方法mark(int readAhedLimit)将标记添加到 BufferedReader 的当前位置,您可以使用reset()返回标记。

使用它们时,您必须注意在reset()之前要读取的字符数,您必须将它们指定为函数mark(int readAhedLimit)的参数。

假设限制为 100 个字符,您的代码应如下所示:

class MyFileReader {
    BufferedReader data;
    int maxNumberOfCharacters = 100;

    public MyFileReader(String fileName)
    {
        try{
            FileInputStream fstream = new FileInputStream(fileName);
            data = new BufferedReader(new InputStreamReader(fstream));
            //mark the current position, in this case the beginning of the file
            data.mark(maxNumberOfCharacters);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void resetFile(){
        data.reset();
    }

    public void closeFile()
    {
        try{
            in.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}
于 2016-04-01T08:39:59.890 回答