2010-02-09 26 views
10

我正在写一个Java程序,要求我比较两个文件中的数据。我必须检查文件1的每一行对文件2的每一行,如果我找到一个匹配将它们写入第三个文件。读完文件2后,如何将指针重置为文件开头?如何将文件指针重置为Java中文件的起始位置?

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(); 
     } 
    } 
} 
+0

好的 - 我做了拼写和语法,我没有做格式。 – danben 2010-02-09 04:19:40

+0

我怀疑原始的海报可能会错误地解释这个任务,实际要求的是一个退化的“差异”。这个猜测是基于OP的先前问题和解决方案的比较难度。 – msw 2010-03-19 20:17:21

回答

4

我认为做的最好的事情将是把每一行从文件1到HashMap;那么你可以检查文件2的每一行作为你的HashMap的成员资格,而不是通过文件1的每行读取整个文件一次。

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

+1

+1 - 首先加载文件1效率更高。除非文件可能非常大。 – 2010-02-09 07:18:26

11

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

rewind()seek(0)

1

好,根纳季·S.答案是什么,我会用它来解决你的问题。

我用Java编写的程序,需要我的数据在2个文件

然而相比,我宁可不要再编写这件事。我宁愿使用类似http://code.google.com/p/java-diff-utils/

+1

很高兴知道有一个开源解决这类问题,但GPL许可证类型可能成为使用它的严重问题。 – 2010-02-09 05:23:23

+0

@Gennady - 只有在恐龙之地:-)。但是,严重的是,如果您对GPL不满意,您可以自由开发自己的非GPL库。 – 2010-02-09 06:02:27

+0

@Stephen C,它不是我,它是公司的法律部门:-)但无论如何,GPL要求你的代码变成GPL,这在很多情况下是不合适的。 – 2010-02-09 06:09:34

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() 
    } 

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

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

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

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

如果文件太大,你没有足够的内存,那么你原来的方法永远不会工作。

0

如前所述,有更好的算法 - 调查这些

旁白:

的FileReader没有实现标记和重置,所以trashgod的评论是不准确的。 你必须实现这个版本(使用RandomAccessFile或不是)或包装在BufferedReader中。但是,如果你标记它,后者将把所有东西加载到内存中。

0

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

0

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

0

如果你可以清楚地indentify文件的尺寸可以使用马克(INT readAheadLimit)复位()从类BufferedReader中。 方法mark(int readAhedLimit)将标记添加到您的BufferedReader的当前位置,并且您可以使用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(); 
     } 
    } 
} 
0

如果你只是想将文件指针复位到文件的顶部,重新初始化缓冲的读者。我假设你也在使用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"))); 
} 

通过重新初始化缓冲读者,您将文件读取器标记/指针复位到文件的顶部,你将不必重新编译的文件来设置文件读取的标记/指针的开始/顶文件。 只有当您不想重新编译并在同一运行中拉出相同的特技时,您才需要重新初始化缓冲区读取器。但是如果你只想运行一次循环,那么你就不必这么做,只需重新编译文件,文件读取器标记就会被设置为文件的顶部/开始。

相关问题