stream.CopyAsync(streamDestination) 其抛出Stream不支持读取异常

stream.CopyAsync(streamDestination) its throw Stream does not support reading exception

我正在尝试为 gzip 压缩文件,但是在压缩之后我需要生成 gzip 字节以生成 base64 字符串。

然而,当我尝试将 gzip 流复制到内存流时,它抛出异常 Stream does not support reading。

我找不到解决这个问题的方法,有人可以帮助我吗?

遵循以下代码:

    public static async Task<Tuple<bool, string, string>> CompressToGzipBase64(this IFormFile formFile, Language language)
    {
        var filePath = formFile.FileName + ".gz";

        try
        {
            await using var gzipFileStream = File.OpenWrite(formFile.FileName + ".gz");
            await using var gZipStream = new GZipStream(gzipFileStream, CompressionMode.Compress);
            await formFile.CopyToAsync(gZipStream);

            var bytesOfFile = await ConverteStreamToByteArray(gZipStream);

            var fileInBase64 = Convert.ToBase64String(bytesOfFile);

            File.Delete(filePath);

            return new Tuple<bool, string, string>(true, fileInBase64, string.Empty);
        }
        catch (Exception e)
        {
            File.Delete(filePath);

            return language switch
            {
                Language.PtBr => new Tuple<bool, string, string>(false, string.Empty,
                    "Ocorreu um erro durante a conversão do arquivo para o formato Gzip. Por favor tente a operação novamente!"),
                Language.EnUs => new Tuple<bool, string, string>(false, string.Empty,
                    "An error occurred while converting the file to Gzip format. Please try the operation again!"),
                Language.EsEs => new Tuple<bool, string, string>(false, string.Empty,
                    "Se produjo un error al convertir el archivo a formato Gzip. ¡Intente la operación nuevamente!"),
                _ => new Tuple<bool, string, string>(false, string.Empty, string.Empty)
            };
        }
    }

    private static async Task<byte[]> ConverteStreamToByteArray(GZipStream stream)
    {
        await using var ms = new MemoryStream();
        await stream.CopyToAsync(ms);
        return ms.ToArray();
    }

您无法从压缩模式下的 GzipStream 中读取,因为它是一个转换流,而不是数据所在的位置。您的数据实际上在 FileStream 中,因此您需要从中读取数据。

但是你甚至不需要 FileStream,因为你没有对文件做任何事情,因为你最后要删除它。 FileStream 只是不必要的,因为它需要写入非常低效的磁盘。

那就这样吧:

await using var compressedStream = new MemoryStream();
await using var gZipStream = new GZipStream(compressedStream, CompressionMode.Compress);
await formFile.CopyToAsync(gZipStream);

var bytesOfFile = compressedStream.ToArray();

var fileInBase64 = Convert.ToBase64String(bytesOfFile);

此外,我建议使用值元组而不是元组,因为它们更简洁、更高效且更易读,因为您可以命名元素。

因此您的整个代码可以改进为:

public static async Task<(bool success, string base64, string error)> CompressToGzipBase64(this IFormFile formFile, Language language)
{
    try
    {
      await using var compressedStream = new MemoryStream();
      await using var gZipStream = new GZipStream(compressedStream, CompressionMode.Compress);
      await formFile.CopyToAsync(gZipStream);

      var bytesOfFile = compressedStream.ToArray();

      var fileInBase64 = Convert.ToBase64String(bytesOfFile);

      return (true, fileInBase64, string.Empty);
    }
    catch (Exception e)
    {
        return language switch
        {
            Language.PtBr => (false, string.Empty,
                "Ocorreu um erro durante a conversão do arquivo para o formato Gzip. Por favor tente a operação novamente!"),
            Language.EnUs => (false, string.Empty,
                "An error occurred while converting the file to Gzip format. Please try the operation again!"),
            Language.EsEs => (false, string.Empty,
                "Se produjo un error al convertir el archivo a formato Gzip. ¡Intente la operación nuevamente!"),
            _ => (false, string.Empty, string.Empty)
        };
    }
}

你可以这样调用它:

var (success, base64, error) = await formFile.CompressToGzipBase64(Language.EnUs); 

另一个建议:不要只是丢弃异常消息。您应该在某处记录异常或在错误消息中包含异常文本。这使得抛出异常时的调试和生活变得更加容易,因为您不需要猜测 error/exception 真正发生了什么。