在文件流或字节数组中更改文件名以通过 WebAPI 发送

问题描述

我想获取文件内容并在内存中重命名文件,以便使用 API 以不同的文件名发送。

目标:

  1. 不得以任何方式更改原始文件(磁盘上的文件)。
  2. 不创建其他文件(例如具有新名称文件副本)。我正在尝试将 IO 访问保持在尽可能低的水平,并在内存中执行所有操作。
  3. 文件对象(在内存中)的名称更改为其他名称
  4. 文件对象上传到另一台机器上的 WebAPI。
  5. 在源 MachineA 上有“FileA.txt”,在目标 MachineB 上有“FileB.txt”。

我认为这无关紧要,但我不打算用新名称文件写回系统(MachineA),它只会用于通过 a 将文件对象(在内存中)发送到 MachineB网络 API。

我找到了一个使用反射来实现这一点的解决方案...

FileStream fs = new FileStream(@"C:\myfile.txt",FileMode.Open);

var myField = fs.GetType()
    .GetField("_fileName",BindingFlags.Instance | BindingFlags.NonPublic)

myField.SetValue(fs,"my_new_filename.txt");

然而,这个解决方案已经过去几年了。 2021 年有没有更好的方法来做到这一点?

解决方法

另一种方法是在将文件保存在 MachineB 上时定义文件名。 您可以将此文件名作为有效负载通过 Web API 传递,并将其用作文件名。

//buffer as byte[] and fileName as string would come from the request
using (FileStream fs = new FileStream(fileName,FileMode.Create))
{
    fs.Write(buffer,buffer.Length);
}
,

我能想到的最好方法是使用我多年前的旧方法。下面显示了我是如何使用它的。我这样做只是为了从我将其发送到的第三方 WebAPI 中屏蔽原始文件名。

// filePath: c:\test\my_secret_filename.txt

private byte[] GetBytesWithNewFileName(string filePath)
{
    byte[] file = null;

    using (var fs = new FileStream(filePath,FileMode.Open,FileAccess.Read))
    {
        // Change the name of the file in memory (does not affect the original file)
        var fileNameField = fs.GetType().GetField(
            "_fileName",BindingFlags.Instance | BindingFlags.NonPublic
        );
        // If I leave out the next line,the file name field will have the full filePath
        // string as its value in the resulting byte array.  This will replace that with
        // only the file name I wish to pass along "my_masked_filename.txt".
        fileNameField.SetValue(fs,"my_masked_filename.txt");

        // Get the filesize of the file and make sure it's compatible with 
        // the binaryreader object to be used
        int fileSize;
        try { fileSize = Convert.ToInt32(fs.Length); }
        catch(OverflowException)
        { throw new Exception("The file is to big to convert using a binary reader."); }

        // Get the file into a byte array
        using (var br = new BinaryReader(fs)) { file = br.ReadBytes(fileSize); }
    }

    return file;
}