Recipe 12.6. Accessing Part of a File RandomlyProblemWhen reading a file, you sometimes need to move from the current position in a file to a position some number of characters before or after the current position, including to the beginning or the end of a file. After moving to this point, you can add, modify, or read the information at this new point in the file. SolutionTo move around in a stream, use the Seek method. The following method writes the string contained in the variables theFirstLine and theSecondLine to a file in this same order. The stream is then flushed to the file on disk: public static void CreateFile(string theFirstLine, int theSecondLine) { using (FileStream fileStream = new FileStream("data.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { using (StreamWriter streamWriter = new StreamWriter(fileStream)) { streamWriter.WriteLine(theFirstLine); streamWriter.WriteLine(theSecondLine); streamWriter.Flush( ); } } } If the following code is used to call this method: CreateFile("This is the first line.", 1020304050); the resulting data.txt file will contain the following text: This is the first line. 1020304050 The ModifyFile method, shown in Example 12-2, uses the Seek method to reposition the current file position at the end of the first line. A new line of text is then added between the first and second lines of text in the file. Finally, the Seek method is used to place the current position pointer in the file to the end, and a final line of text is written to this file. Example 12-2. ModifyFile method
If the following code is used to call this method: ModifyFile(1020304050); the resulting data.txt file will contain the following text: This is the first line. This line added by seeking -12 chars from the end of this file. This is the last line, added by seeking to the end of the file. The next method, ReadFile, reads the file that we just created. First, the current position pointer in the file is moved to the end of the first line (this line contains the string in the variable theFirstLine). The ReadToEnd method is invoked reading the rest of the file (the second and third lines in the file) and the results are displayed: public static void ReadFile(string theFirstLine) { using (StreamReader streamReader = new StreamReader("data.txt")) { streamReader.BaseStream.Seek( theFirstLine.Length + Environment.NewLine.Length, SeekOrigin.Begin); Console.WriteLine(streamReader.ReadToEnd( )); } } The following text is displayed: This line added by seeking -12 chars from the end of this file. This is the last line, added by seeking to the end of the file. If you are wondering where the line of text that reads: 1020304050 is located, it was overwritten when we did the first Seek while writing data to this file. DiscussionFile seeking is the placement of the pointer to the current location in an opened file anywhere betweenand includingthe beginning and ending bytes of a file. Seeking is performed through the use of the Seek method. This method returns the new location of the file pointer in the file. Seeking is performed in one of three ways: as an offset from the beginning of the file, as an offset from the end of the file, or as an offset from the current location in the file, as shown here: public static void MoveInFile(int offsetValue) { Using (FileStream fileStream = File.Open("data.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.None)); { Using (StreamWriter streamWriter = new StreamWriter(fileStream)) { // Move from the beginning of the file. streamWriter.BaseStream.Seek(offsetValue, SeekOrigin.Begin); // Move from the end of the file. streamWriter.BaseStream.Seek(offsetValue, SeekOrigin.End); // Move from the current file pointer location in the file. streamWriter.BaseStream.Seek(offsetValue, SeekOrigin.Current); } } } offsetValue may be any positive or negative number as long as it does not attempt to force the file pointer before the beginning of the file or after the end. The SeekOrigin.Begin enumeration value starts the offset at the beginning of the file; likewise, the SeekOrigin.End value starts the offset at the end of the file. The SeekOrigin.Current value starts the offset at the current location of the file pointer. You must take extra care not to force the file pointer to a point before the start of the file when using the seek method with a negative offset, since this action could move the file pointer before the beginning of the file. If you think about it logically, you should be giving positive values when specifying SeekOrigin.Begin and negative values when specifying SeekOrigin.End; any value makes sense for SeekOrigin.Current, so long as it doesn't cause the pointer to roll past the beginning of the file. To prevent an IOException from being thrown in this circumstance, you can test for this condition in the manner shown in Example 12-3. Example 12-3. Testing for the beginning or end of a file
To seek to the beginning of a file, use the following code: streamWriter.BaseStream.Seek(0, SeekOrigin.Begin); To seek to the end of a file, use the following code: streamWriter.BaseStream.Seek(0, SeekOrigin.End); In these calls, the SeekOrigin enumeration value sets the file pointer to the beginning or end of a file. The offset, which is zero, does not force the file pointer to move. With this in mind, realize that using zero as an offset to SeekOrigin.Current is pointless because you don't move the pointer at all, and you are killing clock cycles to no effect. See AlsoSee the "FileStream Class," "StreamReader Class," "StreamWriter Class," "BinaryReader Class," "BinaryWriter Class," and "SeekOrigin Enumeration" topics in the MSDN documentation. |