【问题标题】:Editing a line in a file by its number [duplicate]按编号编辑文件中的一行[重复]
【发布时间】:2017-05-29 18:33:20
【问题描述】:

我必须编写一个字符串的实现,将它的值存储在硬盘驱动器而不是 ram 上(我知道这听起来很愚蠢,但它旨在教我们不同的排序算法如何在 ram 和硬盘驱动器上工作)。这是我到目前为止所写的:

class HDDArray : IEnumerable<int>
{
    private string filePath;

    public int this[int index]
    {
        get
        {
            using (var reader = new StreamReader(filePath))
            {
                string line = reader.ReadLine();

                for (int i = 0; i < index; i++)
                {
                    line = reader.ReadLine();
                }

                return Convert.ToInt32(line);
            }
        }
        set
        {
            using (var fs = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                var reader = new StreamReader(fs);
                var writer = new StreamWriter(fs);

                for (int i = 0; i < index; i++)
                {
                    reader.ReadLine();
                }

                writer.WriteLine(value);
                writer.Dispose();
            }
        }
    }

    public int Length
    {
        get
        {
            int length = 0;

            using (var reader = new StreamReader(filePath))
            {
                while (reader.ReadLine() != null)
                {
                    length++;
                }
            }

            return length;
        }
    }

    public HDDArray(string file)
    {
        filePath = file;

        if (File.Exists(file))
            File.WriteAllText(file, String.Empty);
        else
            File.Create(file).Dispose();
    }

    public IEnumerator<int> GetEnumerator()
    {
        using (var reader = new StreamReader(filePath))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                yield return Convert.ToInt32(line);
            }
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

我面临的问题是在尝试编辑一行时(在索引器的设置部分中)我最终添加了一个新行而不是编辑旧行(原因很明显,我就是不能弄清楚如何解决它)。

【问题讨论】:

    标签: c#


    【解决方案1】:

    您的数组旨在处理整数。这样的类很容易创建,因为所有数字的长度都是 4 个字节。

    class HDDArray : IEnumerable<int>, IDisposable
    {
        readonly FileStream stream;
        readonly BinaryWriter writer;
        readonly BinaryReader reader;
    
        public HDDArray(string file)
        {
            stream = new FileStream(file, FileMode.Create, FileAccess.ReadWrite);
            writer = new BinaryWriter(stream);
            reader = new BinaryReader(stream);
        }
    
        public int this[int index]
        {
            get
            {
                stream.Position = index * 4;
                return reader.ReadInt32();
            }
            set
            {
                stream.Position = index * 4;
                writer.Write(value);
            }
        }
    
        public int Length
        {
            get
            {
                return (int)stream.Length / 4;
            }
        }
    
        public IEnumerator<int> GetEnumerator()
        {
            stream.Position = 0;
            while (reader.PeekChar() != -1)
                yield return reader.ReadInt32();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        public void Dispose()
        {
            reader?.Dispose();
            writer?.Dispose();
            stream?.Dispose();
        }
    }
    

    由于每个数组元素的大小是已知的,我们可以通过更改其Position 属性简单地移动到流。

    BinaryWriterBinaryReader 非常适合书写和阅读数字。

    开流是一项非常繁重的操作。因此,在创建类时执行一次。在工作结束时,你需要自己清理之后。于是我实现了IDisposable接口。

    用法:

    HDDArray arr = new HDDArray("test.dat");
    
    Console.WriteLine("Length: " + arr.Length);
    
    for (int i = 0; i < 10; i++)
        arr[i] = i;
    
    Console.WriteLine("Length: " + arr.Length);
    
    foreach (var n in arr)
        Console.WriteLine(n);
    
    // Console.WriteLine(arr[20]); // Exception!
    
    arr.Dispose(); // release resources
    

    【讨论】:

    • 我必须将 Encoding.ASCII 添加到 writer 和 reader 以使其不会崩溃。似乎工作正常,谢谢。
    【解决方案2】:

    我有待纠正,但我认为没有一种简单的方法可以重写特定行,因此您可能会发现重写文件更容易——修改该行。

    您可以按如下方式更改您的设置代码:

      set
      {
        var allLinesInFile = File.ReadAllLines(filepath);
        allLinesInFile[index] = value;
        File.WriteAllLines(filepath, allLinesInFile);
      }
    

    不用说应该有一些安全检查来检查文件是否存在和index &lt; allLinesInFile.Length

    【讨论】:

    • 当然,如果数据在磁盘上的原因是因为它不适合内存,这将是一个小问题。可以从一个文件流式传输到第二个文件,然后将新文件重命名为旧文件。
    • 好点@BenVoigt,如果有问题的文件可能非常大,写入临时文件将是一个更好的解决方案。
    【解决方案3】:

    我认为,为了完成排序算法的作业,您不必担心内存大小问题。

    当然,请添加现有的检查文件以供阅读。

    注意:示例中的行数从 0 开始。

    string[] lines = File.ReadAllLines(filePath);
    
    using (StreamWriter writer = new StreamWriter(filePath))
    {
       for (int currentLineNmb = 0; currentLineNmb < lines.Length; currentLineNmb++ )
       {
           if (currentLineNmb == lineToEditNmb)
           {
              writer.WriteLine(lineToWrite);
              continue;
           }
           writer.WriteLine(lines[currentLineNmb]);                
       }
    }
    

    【讨论】:

      猜你喜欢
      • 2022-08-17
      • 2012-02-18
      • 2016-06-29
      • 2013-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-20
      • 2018-01-26
      相关资源
      最近更新 更多