출처 : http://www.javapractices.com/topic/TopicAction.do?Id=42
Reading and writing text files
When reading and writing text files :
- it's almost always a good idea to use buffering (default size is 8K)
- it's often possible to use references to abstract base classes, instead of references to specific concrete classes
- there is always a need to pay attention to exceptions (in particular, IOException and FileNotFoundException)
- always needs to be called, or else resources will leak
- will automatically flush the stream, if necessary
- calling close on a "wrapper" stream will automatically call close on its underlying stream
- closing a stream a second time has no consequence
- Scanner - allows reading files in a compact way
- BufferedReader - readLine
- BufferedWriter - write + newLine
FileInputStream fis = new FileInputStream("test.txt");
InputStreamReader in = new InputStreamReader(fis, "UTF-8");
FileOutputStream fos = new FileOutputStream("test.txt");
OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8");
Scanner scanner = new Scanner(file, "UTF-8");
The following examples use JDK 1.5.
Example 1
Here is a fairly compact example of reading and writing a text file, using an explicit encoding. If you remove all references to encoding from this class, it will still work -- the system's default encoding will simply be used instead.
import java.io.*; import java.util.Scanner; /** Read and write a file using an explicit encoding. Removing the encoding from this code will simply cause the system's default encoding to be used instead. */ public final class ReadWriteTextFileWithEncoding { /** Requires two arguments - the file name, and the encoding to use. */ public static void main(String... aArgs) throws IOException { String fileName = aArgs[0]; String encoding = aArgs[1]; ReadWriteTextFileWithEncoding test = new ReadWriteTextFileWithEncoding( fileName, encoding ); test.write(); test.read(); } /** Constructor. */ ReadWriteTextFileWithEncoding(String aFileName, String aEncoding){ fEncoding = aEncoding; fFileName = aFileName; } /** Write fixed content to the given file. */ void write() throws IOException { log("Writing to file named " + fFileName + ". Encoding: " + fEncoding); Writer out = new OutputStreamWriter(new FileOutputStream(fFileName), fEncoding); try { out.write(FIXED_TEXT); } finally { out.close(); } } /** Read the contents of the given file. */ void read() throws IOException { log("Reading from file."); StringBuilder text = new StringBuilder(); String NL = System.getProperty("line.separator"); Scanner scanner = new Scanner(new File(fFileName), fEncoding); try { while (scanner.hasNextLine()){ text.append(scanner.nextLine() + NL); } } finally{ scanner.close(); } log("Text read in: " + text); } // PRIVATE private final String fFileName; private final String fEncoding; private final String FIXED_TEXT = "But soft! what code in yonder program breaks?"; private void log(String aMessage){ System.out.println(aMessage); } }
Example 2
This example uses FileReader and FileWriter, which implicitly use the system's default encoding. To make this example compatible with JDK 1.4, just change StringBuilder to StringBuffer:
import java.io.*; public class ReadWriteTextFile { /** * Fetch the entire contents of a text file, and return it in a String. * This style of implementation does not throw Exceptions to the caller. * * @param aFile is a file which already exists and can be read. */ static public String getContents(File aFile) { //...checks on aFile are elided StringBuilder contents = new StringBuilder(); try { //use buffering, reading one line at a time //FileReader always assumes default encoding is OK! BufferedReader input = new BufferedReader(new FileReader(aFile)); try { String line = null; //not declared within while loop /* * readLine is a bit quirky : * it returns the content of a line MINUS the newline. * it returns null only for the END of the stream. * it returns an empty String if two newlines appear in a row. */ while (( line = input.readLine()) != null){ contents.append(line); contents.append(System.getProperty("line.separator")); } } finally { input.close(); } } catch (IOException ex){ ex.printStackTrace(); } return contents.toString(); } /** * Change the contents of text file in its entirety, overwriting any * existing text. * * This style of implementation throws all exceptions to the caller. * * @param aFile is an existing file which can be written to. * @throws IllegalArgumentException if param does not comply. * @throws FileNotFoundException if the file does not exist. * @throws IOException if problem encountered during write. */ static public void setContents(File aFile, String aContents) throws FileNotFoundException, IOException { if (aFile == null) { throw new IllegalArgumentException("File should not be null."); } if (!aFile.exists()) { throw new FileNotFoundException ("File does not exist: " + aFile); } if (!aFile.isFile()) { throw new IllegalArgumentException("Should not be a directory: " + aFile); } if (!aFile.canWrite()) { throw new IllegalArgumentException("File cannot be written: " + aFile); } //use buffering Writer output = new BufferedWriter(new FileWriter(aFile)); try { //FileWriter always assumes default encoding is OK! output.write( aContents ); } finally { output.close(); } } /** Simple test harness. */ public static void main (String... aArguments) throws IOException { File testFile = new File("C:\\Temp\\blah.txt"); System.out.println("Original file contents: " + getContents(testFile)); setContents(testFile, "The content of this file has been overwritten..."); System.out.println("New file contents: " + getContents(testFile)); } }
Example 3
This example demonstrates using
Scanner to read a file containing lines of structured data. Each line is then parsed using a second Scanner and a simple delimiter character, used to separate each line into a name-value pair. The Scanner class is used only for reading, not for writing.
import java.io.*; import java.util.Scanner; public final class ReadWithScanner { public static void main(String... aArgs) throws FileNotFoundException { ReadWithScanner parser = new ReadWithScanner("C:\\Temp\\test.txt"); parser.processLineByLine(); log("Done."); } /** * @param aFileName full name of an existing, readable file. */ public ReadWithScanner(String aFileName){ fFile = new File(aFileName); } /** Template method that calls {@link #processLine(String)}. */ public final void processLineByLine() throws FileNotFoundException { Scanner scanner = new Scanner(fFile); try { //first use a Scanner to get each line while ( scanner.hasNextLine() ){ processLine( scanner.nextLine() ); } } finally { //ensure the underlying stream is always closed scanner.close(); } } /** * Overridable method for processing lines in different ways. * * <P>This simple default implementation expects simple name-value pairs, separated by an * '=' sign. Examples of valid input : * <tt>height = 167cm</tt> * <tt>mass = 65kg</tt> * <tt>disposition = "grumpy"</tt> * <tt>this is the name = this is the value</tt> */ protected void processLine(String aLine){ //use a second Scanner to parse the content of each line Scanner scanner = new Scanner(aLine); scanner.useDelimiter("="); if ( scanner.hasNext() ){ String name = scanner.next(); String value = scanner.next(); log("Name is : " + quote(name.trim()) + ", and Value is : " + quote(value.trim()) ); } else { log("Empty or invalid line. Unable to process."); } //(no need for finally here, since String is source) scanner.close(); } // PRIVATE // private final File fFile; private static void log(Object aObject){ System.out.println(String.valueOf(aObject)); } private String quote(String aText){ String QUOTE = "'"; return QUOTE + aText + QUOTE; } }
Example run of this class :
Name is : 'height', and Value is : '167cm' Name is : 'mass', and Value is : '65kg' Name is : 'disposition', and Value is : '"grumpy"' Name is : 'this is the name', and Value is : 'this is the value' Done.