从多个线程写入文件 [英] Writing in a file from multiple threads

查看:149
本文介绍了从多个线程写入文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Objective-C上写了一个下载管理器,它在同一时间从多个段下载文件,以提高速度。

I'm writing a download manager in Objective-C which downloads file from multiple segments at the same times in order to improve the speed. Each segement of the file is downloaded in a thread.

首先,我想要将每个段写入不同的文件,并将所有文件放在一起下载。但是由于很多原因,这不是一个好的解决方案。

At first, I thought to write each segment in a different file and to put together all the files at the end of the download. But for many reasons, it's not a good solution.

所以,我正在寻找一种方式写入一个文件在特定的位置,并能够处理多个线程,因为在我的应用程序中,每个段都下载到线程内。
在Java中,我知道 FileChannel 是完美的,但我不知道在Objective-C。

So, I'm searching a way to write in a file at a specific position and which is able to handle multiple thread because in my application, each segment is downloaded inside a thread. In Java, I know that FileChannel does the trick perfectly but I have no idea in Objective-C.

推荐答案

不要忘记,Obj-C基于正常的C,因此我只是写一个自己的类,使用标准C API处理文件I / O,允许你放置当前写入位置在新文件中的任何位置,甚至远远超出当前文件大小(缺少的字节用零字节填充),以及根据需要向前和向后跳转。实现线程安全的最简单的方法是使用锁,这不是必需的最快的方式,但在你的具体情况下,我敢打赌,瓶颈肯定不是线程同步。类可以有如下的头:

Never forget, Obj-C bases on normal C and thus I would just write an own class, that handles file I/O using standard C API, which allows you to place the current write position anywhere within a new file, even far beyond the current file size (missing bytes are filled with zero bytes), as well as jumping forward and backward as you wish. The easiest way to achieve thread-safety is using a lock, this is not necessary the fastest way but in your specific case, I bet that the bottleneck is certainly not thread-synchronization. The class could have a header like this:

@interface MultiThreadFileWriter : NSObject
{
    @private
        FILE * i_outputFile;
        NSLock * i_fileLock;
}
- (id)initWithOutputPath:(NSString *)aFilePath;
- (BOOL)writeBytes:(const void *)bytes ofLength:(size_t)length
    toFileOffset:(off_t)offset;
- (BOOL)writeData:(NSData *)data toFileOffset:(off_t)offset;
- (void)close;
@end

与此类似的实现:

#import "MultiThreadFileWriter.h"

@implementation MultiThreadFileWriter

- (id)initWithOutputPath:(NSString *)aFilePath
{
    self = [super init];
    if (self) {
        i_fileLock = [[NSLock alloc] init];
        i_outputFile = fopen([aFilePath UTF8String], "w");
        if (!i_outputFile || !i_fileLock) {
            [self release];
            self = nil;
        }
    }
    return self;
}

- (void)dealloc
{
    [self close];
    [i_fileLock release];
    [super dealloc];
}

- (BOOL)writeBytes:(const void *)bytes ofLength:(size_t)length
    toFileOffset:(off_t)offset
{
    BOOL success;

    [i_fileLock lock];
    success = i_outputFile != NULL
        && fseeko(i_outputFile, offset, SEEK_SET) == 0
        && fwrite(bytes, length, 1, i_outputFile) == 1;
    [i_fileLock unlock];
    return success;
}

- (BOOL)writeData:(NSData *)data toFileOffset:(off_t)offset
{
    return [self writeBytes:[data bytes] ofLength:[data length]
        toFileOffset:offset
    ];
}

- (void)close
{
    [i_fileLock lock];
    if (i_outputFile) {
        fclose(i_outputFile);
        i_outputFile = NULL;
    }
    [i_fileLock unlock];
}
@end

可以通过各种方式避免锁定。使用大中央调度和块来调度在串行队列上的查找+写操作将工作。另一种方法是使用UNIX(POSIX)文件处理程序而不是标准的C( open() int FILE * fopen()),重复处理程序多次( dup 函数),然后将它们中的每一个放置到不同的文件偏移量,这避免了进一步寻找每个写入操作和锁定,因为POSIX I / O是线程安全的。然而,这两种实现方式会更复杂,更不便于移植,并且不会有可测量的速度改进。

The lock could be avoided in various way. Using Grand Central Dispatch and Blocks to schedule the seek + write operations on a Serial Queue would work. Another way would be to use UNIX (POSIX) file handlers instead of standard C ones (open() and int instead of FILE * and fopen()), duplicate the handler multiple times (dup() function) and then placing each of them to a different file offset, which avoids further seeking operations on each write and also locking, since POSIX I/O is thread-safe. However, both implementations would be somewhat more complicating, less portable and there would be no measurable speed improvement.

这篇关于从多个线程写入文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆