Plik używany przez inny proces podczas wydruku etykiety przesyłki

0

Witam.
Mam odwieczny problem z zapisem/wydrukiem plików, które są używane przez inny proces... Pobieram etykietę z Inpostu poprzez ich API. Dostaje zwrotkę w postaci byte[] i zapisuje to do pliku, aby wydrukować na drukarce etykiet.

var response = INPOST.GetEtykietaPaczkomatByID(item.id);

if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
    File.WriteAllBytes(AppDomain.CurrentDomain.BaseDirectory + $"etykiety\\{fileName}", response.RawBytes);
    
    //DevExpressem drukuje plik na drukarce etykiet
    PdfPrinterSettings ps = new PdfPrinterSettings();
    ps.Settings.PrinterName = c.DrukarkaEtykiet;
    ps.PageOrientation = PdfPrintPageOrientation.Portrait;

    PdfDocumentProcessor pdfDocumentProcessor = new PdfDocumentProcessor();
    pdfDocumentProcessor.LoadDocument(AppDomain.CurrentDomain.BaseDirectory + $"etykiety\\{fileName}");
    pdfDocumentProcessor.Print(ps);
}

Czasem przejdzie, a czasem nie. Nie ma na to reguły. Czy chodzi o próbę wydrukowania pliku, który jeszcze nie został zapisany? Próbowałem dorzucić Thread.Sleep(1000), ale zachowuje się identycznie tak samo - raz przejdzie, a raz nie.

0

Jak tworzysz filename?

2 potencjalne rozwiązania:

Using, np. tak, przy using program sam dba o to aby zrobić dispose itp. na plikach.

https://docs.microsoft.com/pl-pl/dotnet/csharp/programming-guide/file-system/how-to-write-to-a-text-file

using (System.IO.StreamWriter file =
new System.IO.StreamWriter(@"C:\Users\Public\TestFolder\WriteLines2.txt"))
{
foreach (string line in lines)
{
// If the line doesn't contain the word 'Second', write the line to the file.
if (!line.Contains("Second"))
{
file.WriteLine(line);
}
}
}

Ewentualnie użyć LOCK, który czeka aż zasób/plik zostaje zwolniony:
https://docs.microsoft.com/pl-pl/dotnet/csharp/language-reference/keywords/lock-statement

https://codereview.stackexchange.com/questions/49158/writing-to-file-in-a-thread-safe-manner

Podaj jakieś logi z błędem to będzie można coś więcej podpowiedzieć ;-)

1

Nazwa pliku to id dokumentu

string fileName = $"etykieta_{_TrN.TrN_TrNID}.pdf";

Nie rozumiem tylko dlaczego mam się bawić w StreamWriter skoro w dokumentacji .NET, przy WriteAllBytes(), jest napisane: Tworzy nowy plik, zapisuje określoną tablicę bajtową do pliku, a następnie zamyka plik. Jeśli plik docelowy już istnieje, zostanie nadpisany.

2020-06-18 12:32:04.9757|ERROR|System.IO.IOException: Proces nie może uzyskać dostępu do pliku "C:\Program Files (x86)\Comarch ERP Optima\etykiety\etykieta_1464275.pdf", ponieważ jest on używany przez inny proces.
   w System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   w System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   w System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   w System.IO.File.InternalWriteAllBytes(String path, Byte[] bytes, Boolean checkHost)
   w System.IO.File.WriteAllBytes(String path, Byte[] bytes)
   w EuroMagazyn.MainForm.btnConfirm_Click(Object sender, EventArgs e)
2

A potrzebujesz w ogóle ten plik wczytywać z dysku? Etykietę sobie zapis jak chcesz, ale do LoadDocument wrzuć MemoryStream.

0

Teoretycznie i praktycznie nie potrzebuje go wczytywać. Zmieniłem na to co zaproponowałeś i wychodzi na to, że działa. Ciekawi mnie tylko dlaczego StackTrace wskazuje na zapis pliku, skoro to drukarka próbowała go wydrukować, a on był zajęty jeszcze przez proces zapisu? 🤔 Plik w 99% ma około 70kb. Jakim cudem on jeszcze trzymał proces zapisu? Może to mieć coś wspólnego z dyskiem twardym?

1 użytkowników online, w tym zalogowanych: 0, gości: 1