搜索文件中的字符串,并将匹配的行写入Java中的另一个文件

时间:2010-05-18 13:40:22

标签: java file-io

用于搜索文件中的字符串并将匹配字符串的行写入另一个字符串 文件需要15 - 20分钟才能获得70MB(压缩状态)的单个zip文件。 有什么办法可以减少它。

我的源代码:

获取Zip文件条目

zipFile = new ZipFile(source_file_name);

entries = zipFile.entries();

while (entries.hasMoreElements())

{ ZipEntry entry = (ZipEntry)entries.nextElement();

if (entry.isDirectory()) 
{ 
continue; 
} 
searchString(Thread.currentThread(),entry.getName(), new BufferedInputStream (zipFile.getInputStream(entry)), Out_File, search_string, stats); }

zipFile.close();

搜索字符串

public void searchString(Thread CThread, String Source_File, BufferedInputStream in, File outfile, String search, String stats) throws IOException

{ 

    int count = 0; 
    int countw = 0; 
    int countl = 0; 
    String s; 
    String[] str; 
    BufferedReader br2 = new BufferedReader(new InputStreamReader(in)); 
    System.out.println(CThread.currentThread()); 

        while ((s = br2.readLine()) != null) 
        { 
            str = s.split(search); 
            count = str.length - 1; 
            countw += count; //word count 
            if (s.contains(search)) 
            { 
            countl++;  //line count 
            WriteFile(CThread,s, outfile.toString(), search); 
            } 
        } 

    br2.close(); 
    in.close(); 


} 

--------------------------------------------------------------------------------

public void WriteFile(Thread CThread,String line, String out, String search) throws IOException

{ 
    BufferedWriter bufferedWriter = null; 
    System.out.println("writre thread"+CThread.currentThread()); 
    bufferedWriter = new BufferedWriter(new FileWriter(out, true)); 
    bufferedWriter.write(line); 
    bufferedWriter.newLine(); 
    bufferedWriter.flush(); 
} 

请帮帮我。对于使用线程的10个文件,它实际上需要40分钟,在压缩后,对于70MB的单个文件,它需要15到20分钟。任何最小化时间的方法。

5 个答案:

答案 0 :(得分:4)

您正在为您编写的每一行重新打开文件输出句柄。

这可能会产生大量性能影响,远远超过其他性能问题。相反,我建议您创建BufferedWriter 一次(例如,在第一次匹配时),然后保持打开状态,编写每个匹配的行,然后在完成后关闭Writer

此外,取消对flush()的通话;因为对Writer.close()的调用会自动将任何未写入的数据刷新到磁盘,所以不需要刷新每一行。

最后,作为旁注,您的变量和方法命名样式不遵循Java驼峰案例约定;你可能想考虑改变它。

答案 1 :(得分:3)

我不确定您看到的成本是来自磁盘操作还是来自字符串操作。我现在假设问题是字符串,你可以通过编写一个反复运行代码的测试驱动程序来检查它。

我可以告诉你split()在你的情况下会非常昂贵,因为你正在生产你不需要的字符串然后回收它们,从而产生很多开销。您可能希望使用-Xmx增加JVM可用的空间量。

如果您只是通过空格的存在来分隔单词,那么您可以通过使用在循环之前创建的正则表达式匹配器并将其应用于字符串来做得更好。应用于给定字符串时的匹配数将是你的字数,这不应该创建一个字符串数组(这是非常浪费的,你不使用)。您将在JavaDocs中看到,split通过正则表达式工作;这是事实,但拆分会创建额外的步骤来创建单独的字符串,这就是浪费的地方。

您也可以使用正则表达式来搜索匹配而不是包含虽然可能不会明显更快的匹配。

您可以通过使用多个线程来实现并行。但是,如果split()是您悲伤的原因,那么您的问题就是开销和堆空间不足,因此您不一定会从中受益。

更一般地说,如果你需要这么做很多,你可能想用一种对字符串操作更“友好”的语言来编写脚本。 Python中的10行脚本可以更快地完成这项任务。

答案 2 :(得分:1)

哇,你在用这种方法做什么

WriteFile(CThread,s, outfile.toString(), search);

每当您收到包含文字的行时,您就会创建BufferedWriter(new FileWriter(out, true));

只需在searchString方法中创建一个bufferedWriter,然后使用它来插入行。无需一次又一次地打开它。它将大大提高性能。

答案 3 :(得分:0)

这里的一个问题可能是你在写作时停止阅读。我可能会使用一个线程进行读取,另一个线程用于编写文件。作为额外的优化,编写结果的线程可以将它们缓冲到内存中,并将它们作为批处理写入文件,比如每十个条目或其他内容。

在写入线程中,您应该在处理它们之前对传入的条目进行排队。

当然,你应该首先调试花费时间的地方,不管是IO还是别的什么。

答案 4 :(得分:0)

此代码中存在太多潜在的瓶颈,任何人都无法确定关键的内容。因此,您应该分析应用程序以确定导致它变慢的原因。

有了这些信息,请确定问题是在读取ZIP文件,将搜索或写入匹配到输出文件。

(反复打开和关闭输出文件是一个坏主意,但如果只获得少量搜索命中,则对整体性能没有太大影响。)