多个线程可以同时将数据写入文件吗?

时间:2011-12-22 10:20:41

标签: java multithreading file-io concurrency

如果你曾经使用过p2p下载软件,他们可以下载一个带有多线程的文件,而且他们只创建了一个文件,所以我想知道线程如何将数据写入该文件。顺序还是并行?

想象一下,您想要将大型数据库表转储到文件中,以及如何更快地完成这项工作?

5 个答案:

答案 0 :(得分:21)

您可以使用多个线程将a写入文件,例如一个日志文件。但是你必须像@Thilo指出的那样协调你的主题。您需要同步文件访问权限并且只写入整个记录/行,或者您需要有一个策略来将文件的区域分配给不同的线程,例如重新构建具有已知偏移和大小的文件。

由于性能原因很少这样做,因为大多数磁盘子系统在顺序写入时表现最佳,而磁盘IO是瓶颈。如果CPU创建记录或文本行(或网络IO)是它可以帮助的瓶颈。

  

要将大型数据库表转储到文件中的图像,以及如何更快地完成此工作?

顺序编写可能是最快的。

答案 1 :(得分:18)

Java nio包旨在允许这样做。请查看http://docs.oracle.com/javase/1.5.0/docs/api/java/nio/channels/FileChannel.html上的示例。

您可以将一个文件的多个区域映射到不同的缓冲区,每个缓冲区可以由一个单独的线程单独填充。

答案 2 :(得分:2)

同步声明可以实现此目的。尝试下面的代码,我在类似的上下文中使用。

package hrblib;

import java.io.*;

public class FileOp {

    static int nStatsCount = 0;

    static public String getContents(String sFileName) {  

        try {
            BufferedReader oReader = new BufferedReader(new FileReader(sFileName));
            String sLine, sContent = "";
            while ((sLine=oReader.readLine()) != null) {
                sContent += (sContent=="")?sLine: ("\r\n"+sLine);
            }
            oReader.close();
            return sContent;
        }
        catch (IOException oException) {
            throw new IllegalArgumentException("Invalid file path/File cannot be read: \n" + sFileName);
        }
    }
    static public void setContents(String sFileName, String sContent) {
        try {
            File oFile = new  File(sFileName);
            if (!oFile.exists()) {
                oFile.createNewFile();
            }
            if (oFile.canWrite()) {
                BufferedWriter oWriter = new BufferedWriter(new FileWriter(sFileName));
                oWriter.write (sContent);
                oWriter.close();
            }
        }
        catch (IOException oException) {
            throw new IllegalArgumentException("Invalid folder path/File cannot be written: \n" + sFileName);
        }
    }
    public static synchronized void appendContents(String sFileName, String sContent) {
        try {

            File oFile = new File(sFileName);
            if (!oFile.exists()) {
                oFile.createNewFile();
            }
            if (oFile.canWrite()) {
                BufferedWriter oWriter = new BufferedWriter(new FileWriter(sFileName, true));
                oWriter.write (sContent);
                oWriter.close();
            }

        }
        catch (IOException oException) {
            throw new IllegalArgumentException("Error appending/File cannot be written: \n" + sFileName);
        }
    }
}

答案 3 :(得分:1)

这是什么类型的文件?为什么需要用更多线程来喂它?这取决于文件用法的特征(我不知道更好的词)。

通过网络从多个地方传输文件(简称:类似Torrent)

如果要传输现有文件,程序应该

  • 尽快,因为它知道了文件的大小,用空内容创建它:这可以防止以后的磁盘外错误(如果没有足够的空间,它将在创建时出现,然后再下载任何内容它),它也有助于表现;
  • 如果你很好地组织转移(以及为什么不),每个线程将负责文件的不同部分,因此文件写入将是不同的,
  • 即使两个线程以某种方式选择文件的相同部分,也不会导致错误,因为它们为相同的文件位置写入相同的数据。

将数据块附加到文件(简称:记录)

如果线程只是将固定或各种长度信息附加到文件,则应使用公共线程。它应该使用一个相对较大的写缓冲区,因此它可以快速服务客户端线程(只需要接受字符串),并将其清除出最佳调度和块大小。它应该使用专用磁盘甚至是计算机。

此外,可能存在一些性能问题,这就是为什么日志记录服务器,甚至是昂贵的商业服务器。

读写随机时间,随机位置(简称:数据库)

它需要复杂的设计,使用互斥体等,我从来没有做过这种事情,但我可以想象。向Oracle询问一些技巧:)

答案 4 :(得分:0)

您可以让多个线程写入同一个文件 - 但一次只能写一个。在写入文件之前,所有线程都需要进入同步块。

在P2P示例中 - 实现它的一种方法是找到文件的大小并创建该大小的空文件。每个线程都在下载文件的不同部分 - 当需要写入时,它们将进入同步块 - 使用搜索移动文件指针并写入缓冲区的内容。