protected void OpenFile(bool full) { if (reader != null) { reader.Seek(0); } else { try { // We don't actually write to the file, but requesting ReadWrite access ensures // that nobody else has the file open for writing (unless someone else set FileShare.Write, // but that's unlikely, and this program doesn't do that). // // Opening with FileAccess.Read would mean that other programs could have the file open and // modify it, thus invaliding the file offsets stored in the partially-loaded entries. // // We need to open with FileShare.Read because the main window and other programs need to // read the dictionary header to populate the list. (This should probably change.) // Of course, if we're just reading the dictionary header, we only request read access. var access = full ? FileAccess.ReadWrite : FileAccess.Read; // If we're only loading a header, we have to set FileShare.ReadWrite or the call // fails if the file is already open for ReadWrite. // If we can open the file for Read access, it should be safe to read from without it // being modified (when writing to the dictionary, we specify FileShare.None). var share = full ? FileShare.Read : FileShare.ReadWrite; reader = new Utf8LineReader(Path, access, share); } catch (IOException e) { throw new DictionaryLoadException(e.Message, e); } catch (ArgumentException e) { throw new DictionaryLoadException(e.Message, e); } catch (UnauthorizedAccessException e) { throw new DictionaryLoadException(e.Message, e); } } }
/// <summary> /// Writes all entries to a file. There's no way to tell if the dictionary entries have been modified, /// as of yet, so currently we must write the file whether it's necessary or not. /// </summary> /// <param name="path">The file name (relative or absolute) to write to.</param> protected void Write(string path) { // Update the revision ID. Instead of incrementing a number, pick a random GUID and use that. // If incrementing were used, then if a dictionary were copied to a different computer, modified, // and copied back to the original computer, where the dictionary had also been modified, the // cache revision ID on the original computer would still match that of the dictionary file, despite // being invalid. revisionID = Guid.NewGuid().ToString(); // If we're not writing cautiously, we can't read the entries on-demand while the temporary output file // is written. if (path == Path) CloseFile(); PreloadPartialEntries(); Metrics.Measure(string.Format("Writing dictionary {0} to file", this.Name), delegate { // Now dispose of the reader so that we can unlock the file. // The file needs to be truncated anyway, so it's not possible to share the file stream // with the Line Reader. if (reader != null) { reader.Dispose(); reader = null; } using (var stream = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None)) { using (var writer = new LineWriter(stream)) { writer.WriteLine(magicNumber); if (Name != null) writer.WriteLine("name " + Uri.EscapeDataString(Name)); if (Author != null) writer.WriteLine("author " + Uri.EscapeDataString(Author)); if (Url != null) writer.WriteLine("url " + Uri.EscapeDataString(Url)); writer.WriteLine("revision-id " + Uri.EscapeDataString(revisionID)); // TODO: WritePairedProperty writer.WriteLine(string.Format("headwords-hint {0} {1}", forwards.HeadWords, backwards.HeadWords)); if (FirstLanguage != null || SecondLanguage != null) writer.WriteLine(string.Format("languages {0} {1}", Uri.EscapeDataString(FirstLanguage), Uri.EscapeDataString(SecondLanguage))); if (FirstLanguageCode != null || SecondLanguageCode != null) writer.WriteLine(string.Format("language-codes {0} {1}", Uri.EscapeDataString(FirstLanguageCode), Uri.EscapeDataString(SecondLanguageCode))); writer.WriteLine("sorted"); foreach (Entry entry in ForwardsSection) WriteEntry(writer, "f ", entry); foreach (Entry entry in ReverseSection) WriteEntry(writer, "b ", entry); } } }); }
protected void OpenFile(bool full) { if (reader != null) reader.Seek(0); else { try { // We don't actually write to the file, but requesting ReadWrite access ensures // that nobody else has the file open for writing (unless someone else set FileShare.Write, // but that's unlikely, and this program doesn't do that). // // Opening with FileAccess.Read would mean that other programs could have the file open and // modify it, thus invaliding the file offsets stored in the partially-loaded entries. // // We need to open with FileShare.Read because the main window and other programs need to // read the dictionary header to populate the list. (This should probably change.) // Of course, if we're just reading the dictionary header, we only request read access. var access = full ? FileAccess.ReadWrite : FileAccess.Read; // If we're only loading a header, we have to set FileShare.ReadWrite or the call // fails if the file is already open for ReadWrite. // If we can open the file for Read access, it should be safe to read from without it // being modified (when writing to the dictionary, we specify FileShare.None). var share = full ? FileShare.Read : FileShare.ReadWrite; reader = new Utf8LineReader(Path, access, share); } catch (IOException e) { throw new DictionaryLoadException(e.Message, e); } catch (ArgumentException e) { throw new DictionaryLoadException(e.Message, e); } catch (UnauthorizedAccessException e) { throw new DictionaryLoadException(e.Message, e); } } }
protected void CloseFile() { if (reader != null) { reader.Dispose(); reader = null; } }