Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Parallel.for循环解决文件I/O问题_C#_Multithreading_File Io_Parallel Processing_Task Parallel Library - Fatal编程技术网

C# 使用Parallel.for循环解决文件I/O问题

C# 使用Parallel.for循环解决文件I/O问题,c#,multithreading,file-io,parallel-processing,task-parallel-library,C#,Multithreading,File Io,Parallel Processing,Task Parallel Library,我有一个控制台应用程序,计划处理大量平面文件。为了提高性能,我提供了使用并行处理的选项。它极大地提高了性能。然而,当某些迭代复制和删除文件时,它现在会导致奇怪的错误。我不知道为什么会发生这种情况,也不知道如何解决。我不明白为什么迭代分配给的线程会冲突,因为每个文件和关联的ID都不同。以下是我的基本代码和错误: static void Main(string[] args) { Parallel.For(0, fileCount, i =>

我有一个控制台应用程序,计划处理大量平面文件。为了提高性能,我提供了使用并行处理的选项。它极大地提高了性能。然而,当某些迭代复制和删除文件时,它现在会导致奇怪的错误。我不知道为什么会发生这种情况,也不知道如何解决。我不明白为什么迭代分配给的线程会冲突,因为每个文件和关联的ID都不同。以下是我的基本代码和错误:

static void Main(string[] args)
    {
        Parallel.For(0, fileCount, i =>
                        {
                            dxmtId = Convert.ToInt32(dxmtIds[i]);
                            iflId = Convert.ToInt32(iflIds[i]);
                            islId = Convert.ToInt32(islIds[i]);
                            fileName = fileNames[i].ToString();

                            LoadFileIntoDatabase(monitorId, islId, dxmtId, iflId, fileName);

                        });
    }
    private static void LoadFileIntoDatabase (int procId, int islId, int dxmtId, iflId, fileName )
    {
        string fileNameDone = fileName + ".done";

        if (File.Exists(fileName))
        {
             // code for successfully loading file 
             myCommand = @"CMD.EXE";
             ProcessStartInfo startInfo = new ProcessStartInfo(myCommand)
                    {
                        WorkingDirectory = ConfigurationManager.AppSettings["ExportPath"].ToString(),
                        Arguments = @"/c SQLLDR CONTROL=" + controlFileWithPath + " PARFILE=" + parFileWithPath,
                        //RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        UseShellExecute = false,
                        CreateNoWindow = true
                    };

            Process process = new Process();
            process.StartInfo = startInfo;
            process.Start();
            process.WaitForExit();
            exitCode = process.ExitCode;
            try 
            {
                File.Copy(fileName, fileNameDone, true); //rename file to .done
                File.Delete(fileName); //delete original file
            }
            catch (exception ex)
            {
                File.AppendAllText(@"c:\temp\fileerrors.txt", ex.Message + " " + " on copying or deleting file name: " + fileName +  Environment.NewLine);
            }
        }
    }
错误为1)“找不到文件…”或2)“进程无法访问文件…”


关于如何修复/诊断正在发生的情况,有什么建议吗

我认为问题很可能是
File.Copy()
的过程仍然对原始文件有句柄,因此
File.Delete()
失败了

我建议您改用
File.Move()
,因为这实际上不太占用资源。在内部,
File.Move()
使用
Win32Native.MoveFile
函数对文件系统进行重命名。如果使用
File.Copy()
,实际上是在复制磁盘上的数据,这样会占用更多的资源,速度也会更慢。但是,如果需要保留数据的两个副本(在您的示例中似乎并非如此),则应避免使用
File.Move()

您所需的代码更改看起来有点像这样:

try
{
    File.Move(fileName, fileNameDone);
}
您可能还想更仔细地查看
catch
块,更准确地定位已知错误,即

catch (IOException ex)
{
    // specific error type expected
}

希望这能让您更进一步。

在您的
参数中,
controlFileWithPath
等有哪些值?可能需要引用文件路径,例如,如果路径中有空格,则执行命令
cmd.exe/c SQLLDR CONTROL=“c:\temp\some file.txt”
。如果操作确实彼此独立,那么将它们并行化就可以了。但是,如果
SQLLDR
程序试图并行写入数据库,这可能会再次给您带来一些问题。我认为问题很可能是
File.Copy()
的进程可能仍然对原始文件有句柄,因此
File.Delete()
失败,因为复制功能未等待完成。也许您应该使用
File.Move()
来代替(单操作)??。只是一个inkling@MaximilianGerhardt:controlFileWithPath和parFileWithPath是临时元数据文件,其路径是我从另一个函数生成的,未在此代码中列出。它们返回不带空格的路径,例如“c:\\temp\\634b99e3-77a7-43aa-b9d7-c60735c13e48.ctl”,并且仅由sql loader用于加载文件。错误发生在File.Copy/File.Delete语句中,这些语句位于我加载的实际文件(而不是您询问的元数据文件)上。我将不得不研究sqlldr可能并行工作的想法。但我不认为这是默认行为。thanks@jimtollan我以前使用过.Move(),但现在我会再试一次,看看它是否会改变什么。很高兴知道您是否解决了此问题??File.Move正在执行相同的操作。有趣的是,当我查看在catch块中创建的错误文件时,在某些情况下,我看到同一文件的多个错误条目“找不到文件xxxx”,并且在我的输出目录中确实有一个.done文件。因此,它确实工作并移动了文件,但它再次尝试,显然失败了,因为文件不再存在。我检查了我的名单,没有重复的名字。似乎线程正在以某种方式绑定到处理同一个文件。我不明白!当我的应用程序尝试移动文件时,是否可以查看sql loader是否对该文件具有句柄?我有更多的信息,希望有人能正确引导我。1.每一个导致错误的File.Move()语句实际上都是有效的(我不知道该怎么做)。2.当我从代码中取出sql加载器处理时,没有错误。显然,这与启动sql loader的许多线程有关。但我仍然不知道,当文件名不同时,如何尝试两次相同的文件:process.Start();process.WaitForExit()//这是否会导致释放任何句柄?可能是因为fileerrors.txt在前一个错误上被锁定,而随后尝试写入时失败,所以实际发生了错误。看不到任何其他突出的问题我想我已经发现了问题所在。它在我们传递给sql loader的控制文件中。事实证明,这些文件中有多个重复的文件名,所以当并行运行时,可以想象有2个以上的线程试图同时处理同一个文件。我检查文件的存在性,处理它,然后在完成后重命名它,所以可能它后面的线程正在将它放入其中,再次加载它,并尝试在重新命名后重命名它。因此出现“找不到文件”和“拒绝访问”错误。而在连续剧中,自然没有问题。谢谢你的意见。