使用ZXing在C#中按二维码拆分文档时解决‘文件被占用’错误
问题:ZXing识别二维码后移动文件提示“文件被另一进程占用”
需求说明
我想通过二维码拆分文档:所有无二维码的页面归入首个二维码所在文件夹,之后创建新文件夹并对下一个二维码执行相同操作。但使用ZXing识别二维码后,移动带二维码的文件时提示“文件被另一进程占用”。
原代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ZXing; using System.Drawing; using ZXing.QrCode; using System.Threading; using System.IO; namespace zxing_qr { internal class Program { static void Main(string[] args) { string srcDir = @"C:\Users\tirocinio2\Documents\moduli d'intervento"; string[] filenames = System.IO.Directory.GetFiles(srcDir); List<string> buffer = new List<string>(2); for (int i = 0;i< filenames.Length;i++) { string res = decode(filenames, i); Thread.Sleep(50); if (res != null) { buffer.Add(filenames[i]); string dest = creaCartella(); for (int j = 0; j < buffer.Count; j++) { FileInfo file = new FileInfo(buffer[j]); file.MoveTo($@{dest}" + buffer[j].Substring(buffer[j].LastIndexOf('\\'))); } buffer.Clear(); } else { buffer.Add(filenames[i]); } } Console.WriteLine("premi un tasto per continuare"); Console.ReadKey(); } static string creaCartella() { string destDir = DateTime.Now.ToString().Replace(" ","").Replace("/","_").Replace(":","-"); destDir = @"C:\Users\tirocinio2\Documents\output moduli\" + destDir; System.IO.Directory.CreateDirectory(destDir); return destDir; } static string decode(string[] filenames,int i) { BarcodeReader barcodeReader = new BarcodeReader(); Bitmap barcodeBitmap = (Bitmap)Bitmap.FromFile(filenames[i]); Result barcodeResult = barcodeReader.Decode(barcodeBitmap); return barcodeResult.ToString(); } } }
问题原因
- 文件资源未释放:
decode方法中用Bitmap.FromFile加载图片后,未及时释放Bitmap对象,导致系统一直占用文件句柄,移动文件时触发“被另一进程占用”提示。 - 空引用风险:若未识别到二维码,
barcodeResult为null,直接调用ToString()会抛出空引用异常。 - 路径拼接错误:
file.MoveTo($@{dest}" + ...)的插值语法错误,会导致目标路径格式异常。
修复后的代码
using System; using System.Collections.Generic; using System.Drawing; using System.IO; using ZXing; using ZXing.QrCode; namespace zxing_qr { internal class Program { static void Main(string[] args) { string srcDir = @"C:\Users\tirocinio2\Documents\moduli d'intervento"; string[] filenames = Directory.GetFiles(srcDir); List<string> buffer = new List<string>(); for (int i = 0; i < filenames.Length; i++) { string res = DecodeQrCode(filenames[i]); if (!string.IsNullOrEmpty(res)) { buffer.Add(filenames[i]); string destDir = CreateTargetDirectory(); foreach (var filePath in buffer) { string fileName = Path.GetFileName(filePath); string destPath = Path.Combine(destDir, fileName); File.Move(filePath, destPath); } buffer.Clear(); } else { buffer.Add(filenames[i]); } } // 处理最后一批未遇到二维码的文件 if (buffer.Count > 0) { string destDir = CreateTargetDirectory(); foreach (var filePath in buffer) { string fileName = Path.GetFileName(filePath); string destPath = Path.Combine(destDir, fileName); File.Move(filePath, destPath); } } Console.WriteLine("操作完成,按任意键继续"); Console.ReadKey(); } static string CreateTargetDirectory() { string dirName = DateTime.Now.ToString("yyyyMMddHHmmssfff"); string destDir = Path.Combine(@"C:\Users\tirocinio2\Documents\output moduli", dirName); Directory.CreateDirectory(destDir); return destDir; } static string DecodeQrCode(string filePath) { // using语句自动释放Bitmap资源,释放文件句柄 using (Bitmap barcodeBitmap = (Bitmap)Bitmap.FromFile(filePath)) { var barcodeReader = new BarcodeReader { Options = new QrCodeEncodingOptions { TryHarder = true // 提升二维码识别成功率 } }; Result barcodeResult = barcodeReader.Decode(barcodeBitmap); return barcodeResult?.ToString(); // 空值安全访问 } } } }
关键修改点
- 资源自动释放:用
using包裹Bitmap,确保识别完成后立即释放文件句柄,解决文件占用问题。 - 空值安全处理:使用
barcodeResult?.ToString()避免空引用异常。 - 路径拼接优化:用
Path.Combine和Path.GetFileName替代手动字符串拼接,避免路径格式错误。 - 剩余文件处理:增加循环结束后处理缓冲区剩余文件的逻辑,避免遗漏最后一批无二维码的文件。
- 简化文件夹命名:用
yyyyMMddHHmmssfff格式生成唯一文件夹名,省去特殊字符替换的繁琐操作。
内容的提问来源于stack exchange,提问作者Ricc.g
相关产品推荐
相关产品推荐

