【问题标题】:File Copy Program Doesn't Properly Copy File文件复制程序无法正确复制文件
【发布时间】:2016-03-18 10:10:14
【问题描述】:

你好

我一直在开发类似终端的应用程序,以便更好地使用 c# 进行编程,这只是帮助我学习的东西。我决定添加一个功能,将文件原样复制到一个新文件中......它似乎工作得几乎完美。当在 Notepad++ 中打开时,文件的长度仅相隔几行,就实际文件大小而言,非常非常接近相同。但是,该文件的复制副本永远不会运行。它说文件已损坏。我有一种感觉,它在我创建的文件中读取和重写二进制文件的方法中。代码如下,感谢帮助。对于意大利面条代码也很抱歉,当我在搞乱新想法时,我会有点草率。

处理文件复制/写入的类

using System;
using System.IO;
//using System.Collections.Generic;
namespace ConsoleFileExplorer
{
class FileTransfer
{
    private BinaryWriter writer;
    private BinaryReader reader;
    private FileStream fsc;    // file to be duplicated
    private FileStream fsn;    // new location of file 

    int[] fileData;
    private string _file;

    public FileTransfer(String file)
    {
        _file = file;
        fsc = new FileStream(file, FileMode.Open);
        reader = new BinaryReader(fsc);
    }

    // Reads all the original files data to an array of bytes 
    public byte[] ReadAllDataToArray() 
    {
        byte[] bytes = reader.ReadBytes((int)fsc.Length); // reading bytes from the original file
        return bytes;
    }

    // writes the array of original byte data to a new file
    public void WriteDataFromArray(byte[] fileData, string path) // got a feeling this is the problem :p
    {
        fsn = new FileStream(path, FileMode.Create);
        writer = new BinaryWriter(fsn);
        int i = 0;
        while(i < fileData.Length)
        {
            writer.Write(fileData[i]);
            i++;
      }
    }
  }
}

与此类交互的代码。

(Sleep(5000) 是因为我预计第一次尝试时会出错...

                    case '3':
                    Console.Write("Enter source file: ");
                    string sourceFile = Console.ReadLine();
                    if (sourceFile == "")
                    {
                        Console.Clear();
                        Console.ForegroundColor = ConsoleColor.DarkRed;
                        Console.Error.WriteLine("Must input a proper file path.\n");
                        Console.ForegroundColor = ConsoleColor.White;
                        Menu();
                    } else {
                        Console.WriteLine("Copying Data"); System.Threading.Thread.Sleep(5000);
                        FileTransfer trans = new FileTransfer(sourceFile);

                        //copying the original files data
                        byte[] data = trans.ReadAllDataToArray();

                        Console.Write("Enter Location to store data: ");
                        string newPath = Console.ReadLine();

                        // Just for me to make sure it doesnt exit if i forget
                        if(newPath == "")
                        {
                            Console.Clear();
                            Console.ForegroundColor = ConsoleColor.DarkRed;
                            Console.Error.WriteLine("Cannot have empty path.");
                            Console.ForegroundColor = ConsoleColor.White;
                            Menu();
                        } else
                        {
                            Console.WriteLine("Writing data to file"); System.Threading.Thread.Sleep(5000);
                            trans.WriteDataFromArray(data, newPath);
                            Console.WriteLine("File stored.");
                            Console.ReadLine();
                            Console.Clear();
                            Menu();
                        }
                    }
                break;

文件与新文件比较 右键单击 -> 在新选项卡中打开可能是个好主意

Original File

New File

【问题讨论】:

    标签: c# filestream binaryreader binarywriter


    【解决方案1】:

    您没有正确处理文件流和二进制写入器。两者都倾向于缓冲数据(这是一件好事,尤其是当您一次写入一个字节时)。使用using,您的问题应该会消失。当然,除非有人在您阅读文件时正在编辑它。

    BinaryReaderBinaryWriter 不只是写“原始数据”。它们还根据需要添加元数据——它们是为序列化和反序列化而设计的,而不是读取和写入字节。现在,在使用ReadBytesWrite(byte[]) 的特殊情况下,它们实际上只是原始字节;但是仅仅为此使用这些类并没有多大意义。读取和写入字节是每个Stream 提供给您的 事情——包括FileStreams。没有理由在这里使用BinaryReader/BinaryWriter 等等 - 文件流为您提供所需的一切。

    更好的方法是简单地使用

    using (var fsn = ...)
    {
      fsn.Write(fileData, 0, fileData.Length);
    }
    

    甚至只是

    File.WriteAllBytes(fileName, fileData);
    

    也许您认为一次写入一个字节更接近“金属”,但事实并非如此。在此期间,CPU 不会一次将一个字节传递给硬盘驱动器。相反,硬盘驱动器直接从 RAM 复制数据,无需 CPU 干预。而且大多数硬盘驱动器仍然无法从物理介质写入(或读取)任意数量的数据 - 相反,您正在读取和写入整个扇区。如果系统确实一次写入一个字节,您只需一遍又一遍地重写同一个扇区,只是为了再写入一个字节。

    更好的方法是利用打开文件流这一事实,将文件从源流传输到目标,而不是先将所有内容读入内存,然后再将其写回磁盘。

    【讨论】:

    • “也许你认为一次写一个字节更接近金属” 有趣,这正是我的想法。我设计这个项目是为了帮助我从错误中学习更多并变得更好在编程方面,所以我尝试以艰难的方式完成大多数事情......不过我还有另一个问题。在提到的每个上调用 Close() 和 Dispose() 是否与强制它进入 using 语句相同(本质上,不是机械地)?我本来是想放这些的,但一定忘记了。
    • @CorderroArtz 是的,但如果您有明确的范围,则首选using - 它更具弹性 (try...finally) 并且易于阅读和理解。例如,如果您必须在字段中保持流打开(在您的情况下这不是必需的,甚至是不需要的),您会将整个班级标记为IDisposable,并在那里调用相关的Dispose 方法。当然,您可以在父类实例上使用using(或者,再次将它放在实现IDisposable 等的类中)。无需调用 Close - Dispose 处理正确关闭所有内容。
    【解决方案2】:

    C#中有一个File.Copy()方法,可以看这里https://msdn.microsoft.com/ru-ru/library/c6cfw35a(v=vs.110).aspx

    如果您想自己实现它,请尝试在您的方法中放置一个断点并使用调试。这就像一个关于渔夫和上帝的故事,他给了渔夫一根鱼竿——得到一条鱼,而不是真正的鱼。

    另外,看看你 int[] fileData 和 byte[] fileData 里面最后一个方法,也许这是问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-19
      • 2017-04-02
      • 1970-01-01
      • 2019-11-26
      • 2019-06-18
      • 1970-01-01
      • 1970-01-01
      • 2017-09-06
      相关资源
      最近更新 更多