如何在Java中将文件指针重置为文件的开头?

我正在用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(); } } } 

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

rewind()seek(0)

我认为最好的办法是将文件1中的每一行放入HashMap ; 然后你可以检查文件2的每一行是否有HashMap成员资格,而不是为每行文件1读取整个文件一次。

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

显然你可以关闭并重新打开文件,如下所示:

  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方法永远不会有效。

好吧,Gennady S.回答是我用来解决你的问题。

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

但是,我宁愿不再对此进行编码..我宁愿使用像http://code.google.com/p/java-diff-utils/这样的内容

正如其他人所建议的那样,您应该考虑解决问题的其他方法。 对于返回文件中前一个点的具体问题, java.io.FileReaderinheritance了实现此目标的mark()reset()方法。

如上所述,有更好的算法 – 调查这些

在旁边:

FileReader没有实现标记和重置,因此trashgod的注释不准确。 您要么必须实现此版本(使用RandomAccessFile或不使用)或包装在BufferedReader中。 但是,如果你标记它,后者将把整个东西加载到内存中

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

我相信你可以重新初始化文件2文件阅读器,这应该重置它。

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

使用它们你必须要小心要读取的字符数,直到reset() ,你必须指定它们作为函数标记的参数(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(); } } } 

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

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

假设这是您定义缓冲读取器的方式。 现在,这是你如何检查file = 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"))); } 

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