Java - запись в файл
1. обзор
В этом руководстве мы рассмотрим различные способыwrite to a file using Java. Мы будем использоватьBufferedWriter,PrintWriter,FileOutputStream,DataOutputStream,RandomAccessFile,FileChannel и Java 7Files класс полезности.
Мы также рассмотрим блокировку файла во время записи и обсудим некоторые окончательные выводы по записи в файл.
Эта статья является частьюthe “Java – Back to Basic” series здесь для примера.
Дальнейшее чтение:
Java - Добавить данные в файл
Краткое и практическое руководство по добавлению данных в файлы.
FileNotFoundException в Java
Краткое и практическое руководство по FileNotFoundException в Java.
Как скопировать файл с Java
Взгляните на некоторые распространенные способы копирования файлов в Java.
2. Пишите сBufferedWriter
Давайте начнем с простого - и используемBufferedWriter для записиStringto a new file:
public void whenWriteStringUsingBufferedWritter_thenCorrect()
throws IOException {
String str = "Hello";
BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
writer.write(str);
writer.close();
}
Вывод в файл будет:
Hello
Тогда мы можемappend a String to the existing file:
@Test
public void whenAppendStringUsingBufferedWritter_thenOldContentShouldExistToo()
throws IOException {
String str = "World";
BufferedWriter writer = new BufferedWriter(new FileWriter(fileName, true));
writer.append(' ');
writer.append(str);
writer.close();
}
Файл будет тогда:
Hello World
3. Пишите сPrintWriter
Далее - давайте посмотрим, как мы можем использоватьPrintWriter для записи форматированного текста в файл:
@Test
public void givenWritingStringToFile_whenUsingPrintWriter_thenCorrect()
throws IOException {
FileWriter fileWriter = new FileWriter(fileName);
PrintWriter printWriter = new PrintWriter(fileWriter);
printWriter.print("Some String");
printWriter.printf("Product name is %s and its price is %d $", "iPhone", 1000);
printWriter.close();
}
Полученный файл будет содержать:
Some String
Product name is iPhone and its price is 1000$
Обратите внимание, как мы записываем в файл не только необработанную строку, но и некоторый форматированный текст с помощью методаprintf.
Мы можем создать писатель, используяFileWriter,BufferedWriter или дажеSystem.out.
4. Пишите сFileOutputStream
Давайте теперь посмотрим, как мы можем использоватьFileOutputStream вwrite binary data to a file. Следующий код преобразует байты intString и записывает байты в файл, используяFileOutputStream:
@Test
public void givenWritingStringToFile_whenUsingFileOutputStream_thenCorrect()
throws IOException {
String str = "Hello";
FileOutputStream outputStream = new FileOutputStream(fileName);
byte[] strToBytes = str.getBytes();
outputStream.write(strToBytes);
outputStream.close();
}
Вывод в файл, конечно, будет:
Hello
5. Пишите сDataOutputStream
Далее - давайте посмотрим, как мы можем использоватьDataOutputStream для записи строки в файл:
@Test
public void givenWritingToFile_whenUsingDataOutputStream_thenCorrect()
throws IOException {
String value = "Hello";
FileOutputStream fos = new FileOutputStream(fileName);
DataOutputStream outStream = new DataOutputStream(new BufferedOutputStream(fos));
outStream.writeUTF(value);
outStream.close();
// verify the results
String result;
FileInputStream fis = new FileInputStream(fileName);
DataInputStream reader = new DataInputStream(fis);
result = reader.readUTF();
reader.close();
assertEquals(value, result);
}
6. Пишите сRandomAccessFile
Давайте теперь проиллюстрируем, как писать и редактировать внутри существующего файла, а не просто писать в совершенно новый файл или добавлять к существующему. Проще говоря - нам нужен произвольный доступ.
RandomAccessFile позволяет нам писать в определенной позиции в файле с учетом смещения - от начала файла - в байтах. Следующий код записывает целочисленное значение со смещением, заданным в начале файла:
private void writeToPosition(String filename, int data, long position)
throws IOException {
RandomAccessFile writer = new RandomAccessFile(filename, "rw");
writer.seek(position);
writer.writeInt(data);
writer.close();
}
Если мы хотим прочитать int, хранящийся в определенном месте, мы можем использовать следующий метод:
private int readFromPosition(String filename, long position)
throws IOException {
int result = 0;
RandomAccessFile reader = new RandomAccessFile(filename, "r");
reader.seek(position);
result = reader.readInt();
reader.close();
return result;
}
Чтобы протестировать наши функции, давайте напишем целое число, отредактируем его и, наконец, прочитаем его:
@Test
public void whenWritingToSpecificPositionInFile_thenCorrect()
throws IOException {
int data1 = 2014;
int data2 = 1500;
writeToPosition(fileName, data1, 4);
assertEquals(data1, readFromPosition(fileName, 4));
writeToPosition(fileName2, data2, 4);
assertEquals(data2, readFromPosition(fileName, 4));
}
7. Пишите сFileChannel
Если вы имеете дело с большими файлами,FileChannel может быть быстрее, чем стандартный ввод-вывод. Следующий код записываетString в файл, используяFileChannel:
@Test
public void givenWritingToFile_whenUsingFileChannel_thenCorrect()
throws IOException {
RandomAccessFile stream = new RandomAccessFile(fileName, "rw");
FileChannel channel = stream.getChannel();
String value = "Hello";
byte[] strBytes = value.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(strBytes.length);
buffer.put(strBytes);
buffer.flip();
channel.write(buffer);
stream.close();
channel.close();
// verify
RandomAccessFile reader = new RandomAccessFile(fileName, "r");
assertEquals(value, reader.readLine());
reader.close();
}
8. Запись с классомFiles
Java 7 представляет новый способ работы с файловой системой, а также новый служебный класс -Files. Используя классFiles, мы также можем создавать, перемещать, копировать, удалять файлы и каталоги; его также можно использовать для чтения и записи в файл:
@Test
public void givenUsingJava7_whenWritingToFile_thenCorrect()
throws IOException {
String str = "Hello";
Path path = Paths.get(fileName);
byte[] strToBytes = str.getBytes();
Files.write(path, strToBytes);
String read = Files.readAllLines(path).get(0);
assertEquals(str, read);
}
9. Запись во временный файл
Теперь попробуем записать во временный файл. Следующий код создает временный файл и записывает в него строку:
@Test
public void whenWriteToTmpFile_thenCorrect() throws IOException {
String toWrite = "Hello";
File tmpFile = File.createTempFile("test", ".tmp");
FileWriter writer = new FileWriter(tmpFile);
writer.write(toWrite);
writer.close();
BufferedReader reader = new BufferedReader(new FileReader(tmpFile));
assertEquals(toWrite, reader.readLine());
reader.close();
}
Итак, как вы можете видеть - это просто создание временного файла, что интересно и отличается - после этого момента запись в файл такая же.
10. Заблокировать файл перед записью
Наконец, при записи в файл иногда требуется дополнительная уверенность в том, что никто не записывает в этот файл одновременно. По сути - вы должны иметь возможность заблокировать этот файл во время записи.
Давайте воспользуемсяFileChannel, чтобы попытаться заблокировать файл перед записью в него:
@Test
public void whenTryToLockFile_thenItShouldBeLocked()
throws IOException {
RandomAccessFile stream = new RandomAccessFile(fileName, "rw");
FileChannel channel = stream.getChannel();
FileLock lock = null;
try {
lock = channel.tryLock();
} catch (final OverlappingFileLockException e) {
stream.close();
channel.close();
}
stream.writeChars("test lock");
lock.release();
stream.close();
channel.close();
}
Обратите внимание, что если файл уже заблокирован, когда мы пытаемся получить блокировку, будет выданOverlappingFileLockException.
11. Заметки
Изучив так много способов записи в файл, давайте обсудим некоторые важные примечания:
-
Если мы попытаемся прочитать из несуществующего файла, будет выданFileNotFoundException
-
Если мы попытаемся записать в файл, который не существует, файл будет создан первым, и исключение не возникнет.
-
Очень важно закрыть поток после его использования, поскольку он не закрыт неявно, чтобы освободить любые ресурсы, связанные с ним
-
В выходном потоке методclose() вызываетflush() перед освобождением ресурсов, что заставляет любые буферизованные байты записываться в поток.
Глядя на распространенные практики использования, мы видим, например, чтоPrintWriter используется для записи форматированного текста; FileOutputStream для записи двоичных данных; DataOutputStream для записи примитивных типов данных; RandomAccessFile для записи в определенную позицию; FileChannel для более быстрой записи в файлы большего размера. Некоторые из API этих классов допускают больше, но это хорошее место для начала.
12. Заключение
Эта статья иллюстрирует множество вариантов записи данных в файл с использованием Java.
Реализация всех этих примеров и фрагментов кодаcan be found over on GitHub project - это проект на основе Maven, поэтому его должно быть легко импортировать и запускать как есть.