吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 558|回复: 14
收起左侧

[求助] C#写的这两段下载文件后保存为本地文件的代码有什么区别?

[复制链接]
ilovecomputer66 发表于 2024-7-29 07:51
本帖最后由 ilovecomputer66 于 2024-7-29 14:20 编辑

这是从URL下载文件的代码
string requestUrl = httpRequest.RequestUri.ToString();
HttpResponseMessage response = null;
try
{
    var task = httpClient.SendAsync(httpRequest);
    task.Wait();
    response = task.Result;
}
catch (AggregateException ex)
{
    errorString = $"DoGetForDownloadFile请求超时,异常信息为:\n{ex.ToString()}";
    return HttpRequestResultEnum.Timeout;
}
catch (Exception ex)
{
    errorString = $"DoGetForDownloadFile请求发生错误,异常信息为:\n{ex.ToString()}";
    return HttpRequestResultEnum.OtherError;
}


if (response.IsSuccessStatusCode)  判定为true后,执行下面2种不同写法的代码



[C#] 纯文本查看 复制代码
using (Stream stream = response.Content.ReadAsStreamAsync().Result)
{
    using (FileStream fileStream = new FileStream(savePath, FileMode.Create))
    {
        stream.CopyTo(fileStream);
        // 这里需要主动调用,否则在函数return后应该还没有马上释放,立即进行重命名等操作会出问题
        fileStream.Close();
    }
}
errorString = null;
return HttpRequestResultEnum.Ok;



第二种


[C#] 纯文本查看 复制代码
try
{
    Stream stream = response.Content.ReadAsStreamAsync().Result;
    FileStream fileStream = new FileStream(savePath, FileMode.Create);
    stream.CopyTo(fileStream);
    fileStream.Flush();
    fileStream.Close();
    stream.Flush();
    stream.Close();

    errorString = null;
    return HttpRequestResultEnum.Ok;
}
catch (Exception ex)
{
    errorString = $"写入文件发生错误,异常信息为:\n{ex.ToString()}";
    return HttpRequestResultEnum.OtherError;
}



我先不说实际表现是否有区别,如果有是什么区别。免得有人根据结果瞎反推原因

懂得大佬请指教下,这两种写法是否相同,是否会引发错误,谢谢



另外我也不明白,以前从课本学到,这样写using,不是退出using块时,会自动释放资源么?结果实测后发现,就是上面注释写的,不手工写那个close,实际就是没释放,导致后续对文件操作比如重命名会失败并报错
(这时很独立的工具类函数,所有变量仅函数内部用到,外面就传入要下载文件的URL和保存到本地的完整路径)


——————————————————————————————————————————————
鉴于目前大家回复到7楼,且全是错误答案,不得已公布实际效果


其实之前,我跟2-7楼一样,因为课本上教的就应该是第一种写法,而且课本上都没有注释那里close一说。讲的都是退出using块,自动释放资源


但是实测,第一种写法是绝对错误的。首先是注释,不手工写close,就是释放不了,不信你自己试试,在using之外,对这个文件操作,比如重命名,就会提示文件被占用。因为根本没释放


而且,第一个代码目前这样,大概率会出现运行出using块后,文件根本没有生成的情况。而第二种写法不会出现此问题


但是我不知道是为什么。但可以保证这个结论是对的,第一种写法大概率是会出问题



发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

algy5 发表于 2024-7-29 08:48
资源管理:

第一种写法使用了 using 语句。这是一个简洁的方式来确保 stream 和 fileStream 在块退出时被正确释放。using 语句在块结束时会自动调用 Dispose() 方法,即使发生异常也会如此。
第二种写法则显式地调用 Close() 方法来释放资源。这种方法相对更繁琐且容易遗漏资源释放,特别是在处理复杂的异常情况下。
异常处理:

第一种写法依赖 using 语句的自动资源管理机制,因此异常处理更为简洁,只需处理在 using 语句之外的逻辑。
第二种写法显式处理每一个资源的关闭操作,并包含了异常处理逻辑,这样做的一个潜在问题是,如果在 stream.CopyTo(fileStream) 过程中抛出异常,后续的 Flush() 和 Close() 调用可能不会执行,从而导致资源泄露。
关于 using 的行为:
确实,using 语句在退出时会自动释放资源,这是通过调用对象的 Dispose() 方法来实现的。然而,在某些特殊情况下,如文件流的缓冲区尚未完全写入磁盘,调用 Close() 或 Flush() 可以确保所有数据都被写入并且文件被正确关闭。

从你描述的现象来看,如果不显式调用 Close(),文件操作可能会失败,这表明文件流的缓冲区可能尚未完全刷新到磁盘。虽然 Dispose() 会调用 Close(),但为了确保数据一致性和及时释放资源,显式调用 Close() 是一种更为保险的做法。
asq56747277 发表于 2024-7-29 09:13
Jper 发表于 2024-7-29 09:46
第一种using 块内的代码使用完自动释放,第二种需要手动清除缓冲区再close一下
wxk0248 发表于 2024-7-29 10:56
那个close只是一个保险性的操作,二楼的解释是准确的。一般来讲,使用using是明智的做法,也是微软推荐的写法,using本身等价于try{}finally{},即使程序发生异常也能保证文件被释放。
414269678 发表于 2024-7-29 11:01
using就行了, 需要立即写入的地方调用下Flush方法. 没必要自己finally close, 新版的语法using可以补血大括号, 很简略了.
using Stream stream =await response.Content.ReadAsStreamAsync();
using FileStream fileStream = new FileStream(savePath, FileMode.Create);
 楼主| ilovecomputer66 发表于 2024-7-29 14:20
————————————————————————————————
——————————————————————————————————————————————
鉴于目前大家回复到7楼,且全是错误答案,不得已公布实际效果

其实之前,我跟2-7楼一样,因为课本上教的就应该是第一种写法,而且课本上都没有注释那里close一说。讲的都是退出using块,自动释放资源

但是实测,第一种写法是绝对错误的。首先是注释,不手工写close,就是释放不了,不信你自己试试,在using之外,对这个文件操作,比如重命名,就会提示文件被占用。因为根本没释放

而且,第一个代码目前这样,大概率会出现运行出using块后,文件根本没有生成的情况。而第二种写法不会出现此问题

但是我不知道是为什么。但可以保证这个结论是对的,第一种写法大概率是会出问题

 楼主| ilovecomputer66 发表于 2024-7-29 17:09
algy5 发表于 2024-7-29 08:48
资源管理:

第一种写法使用了 using 语句。这是一个简洁的方式来确保 stream 和 fileStream 在块退出时 ...

chatgpt关于编程的回复,一般都是联想推测,不能真的去参考
 楼主| ilovecomputer66 发表于 2024-7-29 18:41
414269678 发表于 2024-7-29 11:01
using就行了, 需要立即写入的地方调用下Flush方法. 没必要自己finally close, 新版的语法using可以补血大括 ...

我也是这么认为的,教科书也这么写的。但实际不是,我1楼补充了
zazakgfh 发表于 2024-7-29 20:49
大概率和系统有关,我就测试过其他的操作文件的代码,win11 会出现这种情况,就是马上删除会显示不存在,然后删除失败,win10 测试就没问题,可能和系统写文件缓存有关
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-14 03:05

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表