C# ASP.NET与MySQL:XLS转CSV后LOAD DATA找不到文件,如何实现有效文件存在等待?
问题场景
你提到自己有个C# ASP.NET网站,负责把选定文件夹里的*.xls转成*.csv,再用MySQL的LOAD DATA把CSV导入数据表。但现在碰到个诡异的问题:明明CSV文件确实在D:\inetpub\wwwroot\public\target_D8BD592B2F99_08-02-2022.csv这个路径下,LOAD DATA却报错找不到文件:
ERROR [HY000] [MySQL][ODBC 5.1 Driver][mysqld-5.1.51-community]File 'D:\inetpub\wwwroot\public\target_D8BD592B2F99_08-02-2022.csv' not found (Errcode: 2)
你试过循环等File.Exists返回true再执行LOAD DATA,但没效果,怀疑是调用时机太早。下面给你几个实用的排查方向:
排查与解决建议
1. 先确认文件真的写完了
File.Exists返回true只代表文件被创建了,但可能写入它的流还没关闭,文件处于“已存在但无法被读取”的状态。MySQL尝试读取时自然会报错。
解决这个问题,首先要确保生成CSV的代码里,所有文件流都正确关闭。最稳妥的方式是用using语句包裹文件操作,它会自动释放资源:
using (var csvWriter = new StreamWriter(outputFilePath)) { // 这里写你的CSV生成逻辑 } // 到这里文件流已经完全关闭,文件写入完成
如果还是不确定,你可以尝试获取文件的独占访问权——能拿到的话,说明文件已经可以被其他进程读取:
bool fileIsReady = false; var timeout = DateTime.Now.Add(TimeSpan.FromMinutes(1)); while (!fileIsReady && DateTime.Now <= timeout) { try { // 尝试以独占方式打开文件 using (var fs = File.Open(outputFilePath, FileMode.Open, FileAccess.Read, FileShare.None)) { fileIsReady = true; } } catch (IOException) { // 文件被占用,等1秒再试 Thread.Sleep(1000); } } if (!fileIsReady) { Response.Write("超时:文件仍被占用,请重试"); Environment.Exit(0); } // 到这里再执行LOAD DATA
2. 检查MySQL服务的目录权限
很多时候这种“文件存在但找不到”的问题,是因为MySQL服务器进程没有访问目标文件夹的权限。
- 找到你的MySQL服务对应的用户(默认可能是
NETWORK SERVICE,或者你自定义的账号) - 右键
D:\inetpub\wwwroot\public\文件夹 → 属性 → 安全 → 添加这个用户,给它读取和列出文件夹内容的权限 - 如果MySQL服务器和你的ASP.NET网站不在同一台机器,那
LOAD DATA INFILE默认读的是MySQL服务器本地的文件。这时候你需要改用LOAD DATA LOCAL INFILE,同时要在ODBC连接字符串里加上Allow Load Local Infile=Yes;Allow User Variables=Yes,或者把CSV上传到MySQL服务器能访问的目录里。
3. 检查SQL语句里的路径转义
Windows路径里的\在SQL语句里需要转义成\\,或者直接用/代替,不然MySQL会把\当成转义符,解析出来的路径就错了:
-- 正确的写法1:转义反斜杠 LOAD DATA INFILE 'D:\\inetpub\\wwwroot\\public\\target_D8BD592B2F99_08-02-2022.csv' INTO TABLE your_table_name; -- 正确的写法2:用斜杠代替 LOAD DATA INFILE 'D:/inetpub/wwwroot/public/target_D8BD592B2F99_08-02-2022.csv' INTO TABLE your_table_name;
4. 用Server.MapPath确保路径正确
如果是Web应用,ASP.NET的应用程序池身份可能会影响路径解析。你可以用Server.MapPath把相对路径转换成绝对路径,避免路径解析错误:
// 假设CSV在网站根目录下的public文件夹里 string absolutePath = Server.MapPath("~/public/target_D8BD592B2F99_08-02-2022.csv"); // 再用absolutePath拼接你的LOAD DATA语句
内容的提问来源于stack exchange,提问作者Iter Lsic Iealf

