为文件上的读写操作实现File类

时间:2014-06-01 09:15:43

标签: c++ multithreading design-patterns file-io raii

我需要实现一个包含常规文本文件的类,该文件对多个线程(例如“读者”线程和“编写器”)的读写操作都有效。

我正在使用visual studio 2010并且只能使用它(VS 2010)拥有的可用库,因此我选择使用std::fstream类进行文件操作以及CreateThread函数和放大器;标题中的CRITICAL_SECTION对象。

我可以先说,我在一开始就寻求一个简单的解决方案 - 只是这样才有效......:)

我的想法如下:

我创建了一个File类,它将文件和“mutex”(CRITICAL_SECTION对象)保存为私有成员。

此外,此类(File类)为“读取器/写入器”线程提供“公共接口”,以便对读取和写入操作执行文件的同步访问。

请参阅File类的头文件:

class File {

    private:
        std::fstream iofile;
        int size;
        CRITICAL_SECTION critical;

    public:
        File(std::string fileName = " ");
        ~File();
        int getSize();

        // the public interface:
        void read();
        void write(std::string str);

};

另见源文件:

#include "File.h"
File :: File(std::string fileName) 
{
    // create & open file for read write and append 
    // and write the first line of the file
    iofile.open(fileName, std::fstream::in | std::fstream::out | std::fstream::app);  // **1)**

    if(!iofile.is_open()) {
        std::cout << "fileName: " << fileName <<  " failed to open! " << std::endl;
      }

    // initialize class member variables
    this->size = 0;
    InitializeCriticalSection(&critical);   
}

File :: ~File()
{
    DeleteCriticalSection(&critical);
    iofile.close();  // **2)**
}

void File :: read()
{
    // lock "mutex" and  move the file pointer to beginning of file
    EnterCriticalSection(&critical);
    iofile.seekg(0, std::ios::beg); 

    // read it line by line
    while (iofile)
    {
        std::string str;
        getline(iofile, str);
        std::cout << str << std::endl;
    }

    // unlock mutex
    LeaveCriticalSection(&critical);

    // move the file pointer back to the beginning of file
    iofile.seekg(0, std::ios::beg); // **3)**

}

void File :: write(std::string str)
{
    // lock "mutex"
    EnterCriticalSection(&critical);

    // move the file pointer to the end of file
    // and write the string str into the end of the file
    iofile.seekg(0, std::ios::end);  // **4)**
    iofile << str;

    // unlock mutex
    LeaveCriticalSection(&critical);
}

所以我的问题是(参见代码中有关问题的数字):

1)我是否需要为我希望执行的读写操作指定其他内容?

2)我需要在破坏者中添加其他任何东西吗?

3)我需要在这里添加什么才能从文件的开头一定发生每次读取操作?

4)我需要在这里修改/添加什么,以便每次写入都发生在文件的末尾(意味着我希望将str字符串附加到文件的末尾)?

5)任何进一步的评论都会很棒:另一种实施方式,优点和进展关于我的实施,要注意等等的缺点'.....

提前致谢,

盖。

1 个答案:

答案 0 :(得分:1)

  1. 您必须处理异常(以及一般错误)。
  2. 不,你的析构函数甚至有多余的东西,如关闭底层的fstream,对象在它的析构函数中自己处理。
  3. 如果您始终想要在文件的开头阅读,只需打开它进行阅读,您就会自动开始阅读。否则,你可以寻求开始并从那里开始阅读。
  4. 您已使用ios::app打开文件,这会导致每个写入操作追加到末尾(包括忽略设置写入位置的搜索操作IIRC)。
  5. 有一堆不会像你想要的那样工作......

    • 最重要的是,您需要定义您需要类的行为,即公共接口是什么。这包括有关磁盘上文件内容的保证。例如,在创建一个没有传递文件名的对象后,应该写什么?这真的应该是一个名字是单个空间的文件吗?此外,如果一个线程想要写两个缓冲区,每个缓冲区包含100个字符,该怎么办?不中断的唯一机会是首先创建一个组合数据的缓冲区,否则它可能会被另一个线程中断。关于你的班级在阅读时应该履行的保证,它会变得更加复杂。
    • 为什么在传递字符串时不使用引用?你的教程应该提一下。
    • 您正在调用代码以在函数范围的开头和结尾处输入和离开临界区。这个操作应该绑定到类的ctor和dtor,用C ++检查RAII习语。
    • 当您使用互斥锁时,您应该记录它应该保护的内容。在这种情况下,我猜这是iofile,对吗?您正在受互斥保护的边界之外访问它...
    • getSize()应该做什么?负面大小表示什么?如果您想用此发出错误信号,那就是例外情况!此外,在打开现有的,可能是非空文件后,大小为零,这对我来说听起来很奇怪。
    • read()不会返回任何数据,它应该做什么?
    • 使用while循环读取内容总是必须具有“try-to-read {use data}”形式,您的形式为“while success {try-to-read; use data;}”,即无法阅读后会使用数据。
    • Streams有一个状态,该状态是粘性的。一旦设置了failbit,它将保持设置状态,直到您明确调用clear()
  6. BTW:这看起来像是日志代码或文件支持的消息队列。两者都可以以线程友好的方式创建,但为了提出建议,您必须告诉我们您实际上要做什么。这也是你应该在课堂上放置评论部分的内容,这样任何读者都可以理解这个意图(现在更重要的是,你要记住它应该是什么)。