我有一个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()
答案 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);
}
}