2017-02-17 2 views
2

Il semble que j'aie atteint un mur de briques en essayant de développer une application Windows Store pour le bureau. J'essaye d'ouvrir un grand fichier journal (100+ Mo) qu'une autre application a ouvert et de faire un traitement en temps réel sur les derniers événements tels qu'ils sont écrits dans le fichier.UWP - Impossible d'ouvrir le fichier à lire si une autre application l'a ouvert.

Avec régulière, non sandbox C#, cela est assez simple:

System.IO.FileStream stream = File.Open("LOGFILE PATH HERE", System.IO.FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 

Malheureusement, dans un UWP, je reçois « UnauthorizedAccessException » chaque fois que je tente d'ouvrir un fichier qui est utilisé par une autre application. J'ai essayé toutes les API dans toutes les combinaisons que j'ai pu trouver, mais je n'ai pas eu de chance, alors je suis venu ici pour quelques suggestions.

Certains de ce que j'ai essayé:

Windows.Storage.Pickers.FileOpenPicker picker = new Windows.Storage.Pickers.FileOpenPicker(); 
picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.List; 
//Prompt the user to open the log file: 
Windows.Storage.StorageFile logFile = await picker.PickSingleFileAsync(); 
picker.FileTypeFilter.Add(".txt"); 

//This won't work in any case, because it doesn't use the handle that the user picked, 
// so the UWP sandboxing blocks it: 
new FileStream(logFile.Path, FileMode.OpenOrCreate, FileAccess.Read); 

//EDIT: These don't work if the file is open either, I must have made a mistake earlier 
await FileIO.ReadBufferAsync(logFile); 
await FileIO.ReadLinesAsync(logFile); 

//These work if the file is not open by another app, but fail if another app has the file open 
await logFile.OpenAsync(Windows.Storage.FileAccessMode.Read); 
await logFile.OpenStreamForReadAsync(); 

rapide Repro:

Ouvrez une fenêtre PowerShell et exécutez cette commande pour maintenir ouverte "test.txt" dans votre répertoire personnel:

$f = [System.IO.File]::Open("test.txt", [System.IO.FileMode]::OpenOrCreate, [System.IO.FileAccess]::Write, [System.IO.FileShare]::ReadWrite); 
+0

Voir ce post: http://stackoverflow.com/questions/4400517/how-can-i-read-a-file-even-when-getting-an-in-use-by-another-process -exception – Sparrow

+0

C'est seulement pour les applications non-UWP, cela ne fonctionnera pas dans ce cas .. c'est la première chose que j'ai essayé. Aussi, j'ai ce code comme exemple de ce qui n'a pas fonctionné dans mon commentaire: * ( –

+0

Man, c'est frustrant .. selon le System.Diagnostics.Stopwatch, ReadBufferAsync prend 100ms pour lire un fichier journal modeste 100MB même sur mon En outre, je suppose que c'est vraiment la mémoire tampon du fichier entier Pendant ce temps, sur les fichiers qui ne sont pas déjà ouverts, la méthode OpenSync (...) de StorageFile prend moins de 2 ms, donc c'est exactement ce dont j'ai besoin –

Répondre

0

J'ai fait un test simple et cela devrait fonctionner. Le test va comme ceci: - ouvrir un fichier.txt avec Notepad, le fichier ne contient qu'une seule ligne de texte, - exécuter l'application avec le code ci-dessous, - choisissez un fichier qui est encore ouvert dans le Bloc-notes, - vous devriez voir dans la sortie de débogage la première ligne et la seconde vide.

Le code:

public async Task GetFile() 
{ 
    Windows.Storage.Pickers.FileOpenPicker picker = new Windows.Storage.Pickers.FileOpenPicker(); 
    picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.List; 
    picker.FileTypeFilter.Add(".txt"); 
    //Prompt the user to open the log file: 
    Windows.Storage.StorageFile logFile = await picker.PickSingleFileAsync(); 

    try 
    { 
     using (var stream = await logFile.OpenStreamForReadAsync()) 
     using (var reader = new StreamReader(stream)) 
     { 
      var line = await reader.ReadLineAsync(); 
      Debug.WriteLine($"The first line: {line} - waiting"); 
      await Task.Delay(10000); 
      line = await reader.ReadLineAsync(); 
      Debug.WriteLine($"The next line: {line} - waiting"); 
     } 
    } 
    catch (Exception exc) 
    { 
     Debug.WriteLine($"Exception {exc.Message}"); 
    } 
} 

Dans le second test je l'ai modifié le fichier dans le Bloc-notes et enregistré, alors que le code frappe au-dessus await Task.Delay(), puis en essayant de lire la deuxième ligne, vous obtiendrez probablement: 'Exception La poignée avec laquelle cet oplock a été associé a été fermée. L'oplock est maintenant cassé. '.

Je vois que vous ne jetez pas les flux, peut-être que le problème est ici? Avez-vous essayé d'utiliser using pour Idisposable?

+0

Merci Romasz.J'ai essayé OpenStreamForReadAsync, cependant, J'ai essayé l'exemple que vous avez fourni, et cela fonctionne pour un document que j'ai ouvert dans le Bloc-notes, mais si je l'ouvre avec une autre application (ou PowerShell), il lance UnauthorizedAccessException . Je suis un débutant en C#, comment dois-je exécuter cette tâche? J'ai fait un gestionnaire d'événement de bouton et juste appelé "attendent GetFile()". Je vais modifier mon message d'origine pour ajouter la commande powershell que j'ai utilisée pour maintenir un fichier ouvert, qui semble reproduire le comportement de l'application de journalisation de grande taille. –

+0

@DebugArnaut Avez-vous essayé avec une autre application ou PowerShell seulement? Powershell autonome ou dans un studio visuel? – Romasz

2

Ce comportement est attendu pour les API Universal à partir de la mise à jour anniversaire. (aka RS1). Les API et les flux Windows.Storage. * Utilisent ce que l'on appelle un modèle "Polite Reader". Dans ce modèle, les lecteurs peuvent être interrompus par un script qui génère les erreurs de rupture OPLOCK. Dans RS1, cela signifie également que les lecteurs sont bloqués si ANY ouvre un handle pour write.

Dans la mise à jour des créateurs (aka RS2), certaines choses changent à ce sujet. Comme la plate-forme universelle a évolué à partir du WinRT d'origine avec une seule application de premier plan, la nécessité de permettre aux applications d'utiliser des modèles plus traditionnels a surgi. Ainsi, dans RS2, nous apportons quelques modifications pour aider dans ce scénario.

  1. Un non modifié lecteur poli ne sera plus ouvert sur l'échec si un écrivain existe déjà. Cependant, les lecteurs auront toujours des pauses oplock si l'écrivain écrit réellement dans le fichier.
  2. Partage Les violations sont adressées directement à l'appelant au lieu d'être traduites dans AccessDenied.(Pour la compatibilité, ce nouveau comportement est bloqué sur l'application appelante déclarant RS2 comme plate-forme testée dans le manifeste des applications)
  3. De nouvelles options StorageOpenOptions sont disponibles pour que les applications puissent modifier leur code afin d'utiliser les nouvelles options pour obtenir un comportement qui ne fonctionne pas. n'impliquent pas les oplocks, optant effectivement hors du comportement OpLock.