进程无法访问该文件,因为另一个调用第二次正在使用该文件

时间:2018-08-01 09:55:51

标签: c# azure-functions

我有一个Azure函数(HttpTrigger),可在Azure存储中创建tar.gz文件。

当我一次触发它时,文件创建成功。但是,如果我再次点击它,则会出现错误:

  

[Info]进程无法访问文件   'D:\ local \ Temp \ myDir \ tarArchive.tar.gz',因为它正在被   另一个过程。

我必须在Azure门户中重新启动该功能才能创建另一个文件。

这是我的代码:

FileStream fs = new FileStream(myDir+"/firstFile", FileMode.Create);
fs.Write(bytesToCompress, 0, bytesToCompress.Length);
fs.Dispose();
FileStream sfs = new FileStream(myDir + "/secondfile", FileMode.Create);
sfs.Dispose();

DirectoryInfo DirectoryOfFilesToBeTarred = new DirectoryInfo(myDir);
FileInfo[] filesInDirectory = DirectoryOfFilesToBeTarred.GetFiles();

string tarArchiveName = myDir + "/tarArchive.tar.gz";

using (Stream targetStream = new GZipOutputStream(File.Create(tarArchiveName)))
 {
    using (TarArchive tarArchive = TarArchive.CreateOutputTarArchive(targetStream, TarBuffer.DefaultBlockFactor))
    {
        foreach(FileInfo fileToBeTarred in filesInDirectory)
        {
           log.Info(fileToBeTarred.FullName);
           TarEntry entry = TarEntry.CreateEntryFromFile(fileToBeTarred.FullName);                            
           tarArchive.WriteEntry(entry, true); // Error thrown here

        }
    }
 }

我认为当再次调用该函数时,fileToBeTarred仍在使用中(我错了吗?),但是我试图从此FileInfo创建一个流,以便对其进行Dispose()处理,但没有解决我的问题。我也尝试过Delete(),没有任何效果。

有人看到我看不到的东西吗?

感谢您的帮助

更新

这是Wim Coenen给出的正确代码

using (Stream fileStream = File.Create(tarArchiveName))
using (Stream targetStream = new GZipOutputStream(fileStream))
using (TarArchive tarArchive = TarArchive.CreateOutputTarArchive(targetStream, TarBuffer.DefaultBlockFactor))
 {
   foreach (FileInfo fileToBeTarred in filesInDirectory)
   {
     log.Info(fileToBeTarred.FullName);
     TarEntry entry = TarEntry.CreateEntryFromFile(fileToBeTarred.FullName);
     tarArchive.WriteEntry(entry, true); // Error thrown here 
   }
}

和错误日志(e =异常对象) e.message =>

  

2018-08-01T11:59:46.887 [Info]进程无法访问文件   'D:\ local \ Temp \ myDir \ tarArchive.tar.gz',因为它正在被   另一个过程。

e.ToString()=>

  

2018-08-01T11:59:47.152 [Info] System.IO.IOException:该过程   无法访问文件'D:\ local \ Temp \ myDir \ tarArchive.tar.gz'   因为它正在被另一个进程使用。

     

在System.IO .__ Error.WinIOError(Int32 errorCode,字符串   也许是完整路径)

     

在System.IO.FileStream.Init(字符串路径,FileMode模式,FileAccess   访问,Int32权限,布尔useRights,FileShare共享,Int32   bufferSize,FileOptions选项,SECURITY_ATTRIBUTES secAttrs,字符串   msgPath,布尔bFromProxy,布尔useLongPath,布尔checkHost)

     

在System.IO.FileStream..ctor(字符串路径,FileMode模式,   FileAccess访问,FileShare共享)

     

在ICSharpCode.SharpZipLib.Tar.TarArchive.WriteEntryCore(TarEntry   sourceEntry,布尔型递归)

     

在ICSharpCode.SharpZipLib.Tar.TarArchive.WriteEntry(TarEntry   sourceEntry,布尔型递归)

     

在UploadFileFromBCText.Function1.d__4.MoveNext()

3 个答案:

答案 0 :(得分:1)

您似乎不是在Azure存储中创建它,而是在Function App实例的本地磁盘上创建它。这可能不是一个好主意,因为实例是短暂的,并且不会长时间保存文件。

相反,请看一下Azure Blob Storage Output binding-它的目的是在不使用低级文件API或SDK的情况下将文件存储在Azure存储中。

答案 1 :(得分:0)

问题是您没有处理File.Create(tarArchiveName))返回的流。固定版本:

using (Stream fileStream = File.Create(tarArchiveName))
using (Stream targetStream = new GZipOutputStream(fileStream))
using (TarArchive tarArchive = TarArchive.CreateOutputTarArchive(targetStream, TarBuffer.DefaultBlockFactor))
{
    foreach(FileInfo fileToBeTarred in filesInDirectory)
    {
        log.Info(fileToBeTarred.FullName);
        TarEntry entry = TarEntry.CreateEntryFromFile(fileToBeTarred.FullName);                            
        tarArchive.WriteEntry(entry, true);
    }
 }

答案 2 :(得分:0)

我刚刚发现了问题所在

实际上,当我第一次按下触发器时,myDir为空。所以我此时创建了两个文件

FileStream fs = new FileStream(myDir+"/firstFile", FileMode.Create);
fs.Write(bytesToCompress, 0, bytesToCompress.Length);
fs.Dispose();
FileStream sfs = new FileStream(myDir + "/secondfile", FileMode.Create);
sfs.Dispose();

使用这些文件,我创建了一个tar.gz存档,其中的目录中还没有这些文件。

第二次我按下触发器时,tar.gz文件存在,并且属于该目录。所以当我这样做

foreach(FileInfo fileToBeTarred in filesInDirectory)
    {
        log.Info(fileToBeTarred.FullName);
        TarEntry entry = TarEntry.CreateEntryFromFile(fileToBeTarred.FullName);                            
        tarArchive.WriteEntry(entry, true);
    }

目前,它可以与tar.gz文件一起使用..!

filesInDiretory通过此方法填充:

FileInfo[] filesInDirectory = DirectoryOfFilesToBeTarred.GetFiles();

所以我通过以下方法解决此问题:

  • 检查文件是否存在。如果是这样,我将其删除。

  • 之后填充文件到目录

所以我的完整代码现在看起来像这样:

        DirectoryInfo DirectoryOfFilesToBeTarred = new DirectoryInfo(myDir);
        string tarArchiveName = myDir + "/tarArchive.tar.gz";
        if (File.Exists(tarArchiveName))
        {
            log.Info("file exists");
            File.Delete(tarArchiveName);

        }
        FileInfo[] filesInDirectory = DirectoryOfFilesToBeTarred.GetFiles();

        using (Stream fileStream = File.Create(tarArchiveName))
        using (Stream targetStream = new GZipOutputStream(fileStream))
        using (TarArchive tarArchive = TarArchive.CreateOutputTarArchive(targetStream, TarBuffer.DefaultBlockFactor))
        {
            foreach (FileInfo fileToBeTarred in filesInDirectory)
            {
                Directory.SetCurrentDirectory(Path.GetTempPath() + "/myDir");
                log.Info(fileToBeTarred.Name);
                log.Info(fileToBeTarred.FullName);
                TarEntry entry = TarEntry.CreateEntryFromFile(fileToBeTarred.FullName);

                tarArchive.WriteEntry(entry, true);


            }

        }