Java Language
Файловый ввод-вывод
Поиск…
Вступление
Java I / O (вход и выход) используется для обработки ввода и вывода вывода. Java использует концепцию потока для быстрой работы ввода-вывода. Пакет java.io содержит все классы, необходимые для операций ввода и вывода. Обработка файлов также выполняется в Java с помощью API ввода-вывода Java.
Чтение всех байтов в байт []
Java 7 представила очень полезный класс файлов
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
Path path = Paths.get("path/to/file");
try {
byte[] data = Files.readAllBytes(path);
} catch(IOException e) {
e.printStackTrace();
}
Чтение изображения из файла
import java.awt.Image;
import javax.imageio.ImageIO;
...
try {
Image img = ImageIO.read(new File("~/Desktop/cat.png"));
} catch (IOException e) {
e.printStackTrace();
}
Запись байта [] в файл
byte[] bytes = { 0x48, 0x65, 0x6c, 0x6c, 0x6f };
try(FileOutputStream stream = new FileOutputStream("Hello world.txt")) {
stream.write(bytes);
} catch (IOException ioe) {
// Handle I/O Exception
ioe.printStackTrace();
}
byte[] bytes = { 0x48, 0x65, 0x6c, 0x6c, 0x6f };
FileOutputStream stream = null;
try {
stream = new FileOutputStream("Hello world.txt");
stream.write(bytes);
} catch (IOException ioe) {
// Handle I/O Exception
ioe.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException ignored) {}
}
}
Большинство API-интерфейсов java.io поддерживают как String
и File
качестве аргументов, поэтому вы также можете использовать
File file = new File("Hello world.txt");
FileOutputStream stream = new FileOutputStream(file);
Stream vs Writer / Reader API
Потоки обеспечивают самый прямой доступ к двоичному содержимому, поэтому любые реализации InputStream
/ OutputStream
всегда работают с int
s и byte
s.
// Read a single byte from the stream
int b = inputStream.read();
if (b >= 0) { // A negative value represents the end of the stream, normal values are in the range 0 - 255
// Write the byte to another stream
outputStream.write(b);
}
// Read a chunk
byte[] data = new byte[1024];
int nBytesRead = inputStream.read(data);
if (nBytesRead >= 0) { // A negative value represents end of stream
// Write the chunk to another stream
outputStream.write(data, 0, nBytesRead);
}
Есть некоторые исключения, возможно, в первую очередь PrintStream
который добавляет «способность печатать представления различных значений данных удобно». Это позволяет использовать System.out
как двоичный InputStream
и как текстовый вывод с использованием таких методов, как System.out.println()
.
Кроме того, некоторые потоковые реализации работают как интерфейс для содержимого более высокого уровня, таких как объекты Java (см. Сериализация) или собственные типы, например DataOutputStream
/ DataInputStream
.
С классами Writer
и Reader
Java также предоставляет API для явных потоков символов. Хотя большинство приложений будут основывать эти реализации на потоках, API потока символов не предоставляет никаких методов для двоичного содержимого.
// This example uses the platform's default charset, see below
// for a better implementation.
Writer writer = new OutputStreamWriter(System.out);
writer.write("Hello world!");
Reader reader = new InputStreamReader(System.in);
char singleCharacter = reader.read();
Всякий раз, когда необходимо кодировать символы в двоичные данные (например, при использовании классов InputStreamWriter
/ OutputStreamWriter
), вы должны указать кодировку, если вы не хотите зависеть от кодировки платформы по умолчанию. Если есть сомнения, используйте кодировку, совместимую с Unicode, например UTF-8, которая поддерживается на всех платформах Java. Поэтому вам следует избегать таких классов, как FileWriter
и FileReader
поскольку они всегда используют кодировку платформы по умолчанию. Лучший способ доступа к файлам с использованием потоков символов - это:
Charset myCharset = StandardCharsets.UTF_8;
Writer writer = new OutputStreamWriter( new FileOutputStream("test.txt"), myCharset );
writer.write('Ä');
writer.flush();
writer.close();
Reader reader = new InputStreamReader( new FileInputStream("test.txt"), myCharset );
char someUnicodeCharacter = reader.read();
reader.close();
Одним из наиболее часто используемых Reader
является BufferedReader
который предоставляет метод для считывания целых строк текста из другого считывателя и, по-видимому, является самым простым способом прочтения потока символов по строкам:
// Read from baseReader, one line at a time
BufferedReader reader = new BufferedReader( baseReader );
String line;
while((line = reader.readLine()) != null) {
// Remember: System.out is a stream, not a writer!
System.out.println(line);
}
Чтение всего файла сразу
File f = new File(path);
String content = new Scanner(f).useDelimiter("\\Z").next();
\ Z - символ EOF (конец файла). При установке в качестве разделителя сканер будет считывать заполнение до тех пор, пока не будет достигнут флаг EOF.
Чтение файла со сканером
Чтение файла по строкам
public class Main {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(new File("example.txt"));
while(scanner.hasNextLine())
{
String line = scanner.nextLine();
//do stuff
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
слово за слово
public class Main {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(new File("example.txt"));
while(scanner.hasNext())
{
String line = scanner.next();
//do stuff
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
и вы также можете изменить делимметр, используя метод scanner.useDelimeter ()
Итерация по каталогу и фильтрация с помощью расширения файла
public void iterateAndFilter() throws IOException {
Path dir = Paths.get("C:/foo/bar");
PathMatcher imageFileMatcher =
FileSystems.getDefault().getPathMatcher(
"regex:.*(?i:jpg|jpeg|png|gif|bmp|jpe|jfif)");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir,
entry -> imageFileMatcher.matches(entry.getFileName()))) {
for (Path path : stream) {
System.out.println(path.getFileName());
}
}
}
Миграция из java.io.File в Java 7 NIO (java.nio.file.Path)
В этих примерах предполагается, что вы уже знаете, что такое NIO для Java 7 в целом, и вы привыкли писать код с помощью java.io.File
. Используйте эти примеры в качестве средства для быстрого поиска дополнительной документации по миграции для NIO.
Существует гораздо больше для NIO Java 7, таких как файлы с отображением памяти или открытие файла ZIP или JAR с помощью FileSystem . Эти примеры будут охватывать только ограниченное число основных случаев использования.
В качестве основного правила, если вы привыкли выполнять операцию чтения / записи файловой системы с помощью метода экземпляра java.io.File
, вы найдете его как статический метод в java.nio.file.Files
.
Укажите путь
// -> IO
File file = new File("io.txt");
// -> NIO
Path path = Paths.get("nio.txt");
Пути по отношению к другому пути
// Forward slashes can be used in place of backslashes even on a Windows operating system
// -> IO
File folder = new File("C:/");
File fileInFolder = new File(folder, "io.txt");
// -> NIO
Path directory = Paths.get("C:/");
Path pathInDirectory = directory.resolve("nio.txt");
Преобразование файла из / в путь для использования с библиотеками
// -> IO to NIO
Path pathFromFile = new File("io.txt").toPath();
// -> NIO to IO
File fileFromPath = Paths.get("nio.txt").toFile();
Проверьте, существует ли файл и удаляет его, если он
// -> IO
if (file.exists()) {
boolean deleted = file.delete();
if (!deleted) {
throw new IOException("Unable to delete file");
}
}
// -> NIO
Files.deleteIfExists(path);
Запись в файл через OutputStream
Существует несколько способов записи и чтения из файла с помощью NIO для различных ограничений производительности, памяти, чтения и использования, таких как FileChannel
, Files.write(Path path, byte\[\] bytes, OpenOption... options)
. В этом примере OutputStream
только OutputStream
, но вам настоятельно рекомендуется узнать о файлах с отображением памяти и различных статических методах, доступных в java.nio.file.Files
.
List<String> lines = Arrays.asList(
String.valueOf(Calendar.getInstance().getTimeInMillis()),
"line one",
"line two");
// -> IO
if (file.exists()) {
// Note: Not atomic
throw new IOException("File already exists");
}
try (FileOutputStream outputStream = new FileOutputStream(file)) {
for (String line : lines) {
outputStream.write((line + System.lineSeparator()).getBytes(StandardCharsets.UTF_8));
}
}
// -> NIO
try (OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE_NEW)) {
for (String line : lines) {
outputStream.write((line + System.lineSeparator()).getBytes(StandardCharsets.UTF_8));
}
}
Итерация по каждому файлу в папке
// -> IO
for (File selectedFile : folder.listFiles()) {
// Note: Depending on the number of files in the directory folder.listFiles() may take a long time to return
System.out.println((selectedFile.isDirectory() ? "d" : "f") + " " + selectedFile.getAbsolutePath());
}
// -> NIO
Files.walkFileTree(directory, EnumSet.noneOf(FileVisitOption.class), 1, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path selectedPath, BasicFileAttributes attrs) throws IOException {
System.out.println("d " + selectedPath.toAbsolutePath());
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path selectedPath, BasicFileAttributes attrs) throws IOException {
System.out.println("f " + selectedPath.toAbsolutePath());
return FileVisitResult.CONTINUE;
}
});
Рекурсивная итерация папок
// -> IO
recurseFolder(folder);
// -> NIO
// Note: Symbolic links are NOT followed unless explicitly passed as an argument to Files.walkFileTree
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
System.out.println("d " + selectedPath.toAbsolutePath());
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path selectedPath, BasicFileAttributes attrs) throws IOException {
System.out.println("f " + selectedPath.toAbsolutePath());
return FileVisitResult.CONTINUE;
}
});
private static void recurseFolder(File folder) {
for (File selectedFile : folder.listFiles()) {
System.out.println((selectedFile.isDirectory() ? "d" : "f") + " " + selectedFile.getAbsolutePath());
if (selectedFile.isDirectory()) {
// Note: Symbolic links are followed
recurseFolder(selectedFile);
}
}
}
Чтение / запись файла с использованием FileInputStream / FileOutputStream
Напишите в файл test.txt:
String filepath ="C:\\test.txt";
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filepath);
byte[] buffer = "This will be written in test.txt".getBytes();
fos.write(buffer, 0, buffer.length);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(fos != null)
fos.close();
}
Читайте из файла test.txt:
String filepath ="C:\\test.txt";
FileInputStream fis = null;
try {
fis = new FileInputStream(filepath);
int length = (int) new File(filepath).length();
byte[] buffer = new byte[length];
fis.read(buffer, 0, length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(fis != null)
fis.close();
}
Обратите внимание, что начиная с Java 1.7 был введен оператор try-with-resources, который значительно упростил реализацию операции чтения / записи:
Напишите в файл test.txt:
String filepath ="C:\\test.txt";
try (FileOutputStream fos = new FileOutputStream(filepath)){
byte[] buffer = "This will be written in test.txt".getBytes();
fos.write(buffer, 0, buffer.length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Читайте из файла test.txt:
String filepath ="C:\\test.txt";
try (FileInputStream fis = new FileInputStream(filepath)){
int length = (int) new File(filepath).length();
byte[] buffer = new byte[length];
fis.read(buffer, 0, length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Чтение из двоичного файла
Вы можете прочитать двоичный файл, используя этот фрагмент кода во всех последних версиях Java:
File file = new File("path_to_the_file");
byte[] data = new byte[(int) file.length()];
DataInputStream stream = new DataInputStream(new FileInputStream(file));
stream.readFully(data);
stream.close();
Если вы используете Java 7 или более позднюю версию, существует более простой способ использования nio API
:
Path path = Paths.get("path_to_the_file");
byte [] data = Files.readAllBytes(path);
Блокировка
Файл можно заблокировать с FileChannel
API FileChannel
который можно получить из входных streams
и readers
Пример с streams
// Открыть файловый поток FileInputStream ios = new FileInputStream (имя файла);
// get underlying channel
FileChannel channel = ios.getChannel();
/*
* try to lock the file. true means whether the lock is shared or not i.e. multiple processes can acquire a
* shared lock (for reading only) Using false with readable channel only will generate an exception. You should
* use a writable channel (taken from FileOutputStream) when using false. tryLock will always return immediately
*/
FileLock lock = channel.tryLock(0, Long.MAX_VALUE, true);
if (lock == null) {
System.out.println("Unable to acquire lock");
} else {
System.out.println("Lock acquired successfully");
}
// you can also use blocking call which will block until a lock is acquired.
channel.lock();
// Once you have completed desired operations of file. release the lock
if (lock != null) {
lock.release();
}
// close the file stream afterwards
// Example with reader
RandomAccessFile randomAccessFile = new RandomAccessFile(filename, "rw");
FileChannel channel = randomAccessFile.getChannel();
//repeat the same steps as above but now you can use shared as true or false as the channel is in read write mode
Копирование файла с помощью InputStream и OutputStream
Мы можем напрямую копировать данные из источника в приемник данных с использованием цикла. В этом примере мы считываем данные из InputStream и в то же время записываем в OutputStream. Когда мы закончим чтение и письмо, мы должны закрыть ресурс.
public void copy(InputStream source, OutputStream destination) throws IOException {
try {
int c;
while ((c = source.read()) != -1) {
destination.write(c);
}
} finally {
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
}
Чтение файла с использованием канала и буфера
Channel
использует Buffer
для чтения / записи данных. Буфер представляет собой контейнер с фиксированным размером, в котором мы можем сразу написать блок данных. Channel
- это гораздо быстрее, чем потоковый ввод-вывод.
Чтобы читать данные из файла с помощью Channel
нам необходимо выполнить следующие шаги:
- Нам нужен экземпляр
FileInputStream
.FileInputStream
имеет метод с именемgetChannel()
который возвращает канал. - Вызовите метод
getChannel()
FileInputStream и приобретите канал. - Создайте ByteBuffer. ByteBuffer - контейнер с фиксированным размером байтов.
- Канал имеет метод чтения, и мы должны предоставить ByteBuffer в качестве аргумента для этого метода чтения. ByteBuffer имеет два режима: настроение только для чтения и настроение только для записи. Мы можем изменить режим с помощью вызова метода
flip()
. Буфер имеет положение, лимит и емкость. Как только буфер создается с фиксированным размером, его предел и емкость совпадают с размером, и позиция начинается с нуля. Пока буфер записывается с данными, его положение постепенно увеличивается. Изменение режима означает изменение положения. Чтобы читать данные с начала буфера, мы должны установить позицию в ноль. flip () изменить позицию - Когда мы вызываем метод чтения
Channel
, он заполняет буфер, используя данные. - Если нам нужно прочитать данные из
ByteBuffer
, нам нужно перевернуть буфер, чтобы изменить его режим на запись только в режим только для чтения, а затем продолжить чтение данных из буфера. - Когда данных больше нет, метод
read()
канала возвращает 0 или -1.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class FileChannelRead {
public static void main(String[] args) {
File inputFile = new File("hello.txt");
if (!inputFile.exists()) {
System.out.println("The input file doesn't exit.");
return;
}
try {
FileInputStream fis = new FileInputStream(inputFile);
FileChannel fileChannel = fis.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (fileChannel.read(buffer) > 0) {
buffer.flip();
while (buffer.hasRemaining()) {
byte b = buffer.get();
System.out.print((char) b);
}
buffer.clear();
}
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Копирование файла с использованием канала
Мы можем использовать Channel
для ускорения копирования содержимого файла. Для этого мы можем использовать метод transferTo()
для FileChannel
.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
public class FileCopier {
public static void main(String[] args) {
File sourceFile = new File("hello.txt");
File sinkFile = new File("hello2.txt");
copy(sourceFile, sinkFile);
}
public static void copy(File sourceFile, File destFile) {
if (!sourceFile.exists() || !destFile.exists()) {
System.out.println("Source or destination file doesn't exist");
return;
}
try (FileChannel srcChannel = new FileInputStream(sourceFile).getChannel();
FileChannel sinkChanel = new FileOutputStream(destFile).getChannel()) {
srcChannel.transferTo(0, srcChannel.size(), sinkChanel);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Чтение файла с использованием BufferedInputStream
Чтение файла с использованием BufferedInputStream
обычно происходит быстрее, чем FileInputStream
потому что он поддерживает внутренний буфер для хранения байтов, считанных из основного входного потока.
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class FileReadingDemo {
public static void main(String[] args) {
String source = "hello.txt";
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source))) {
byte data;
while ((data = (byte) bis.read()) != -1) {
System.out.println((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Запись файла с использованием Channel и Buffer
Для записи данных в файл с использованием Channel
нам необходимо выполнить следующие действия:
- Во-первых, нам нужно получить объект
FileOutputStream
- Приобретите
FileChannel
вызывающий методgetChannel()
изFileOutputStream
- Создайте
ByteBuffer
а затем заполните его данными - Затем мы должны вызвать метод
flip()
ByteBuffer
и передать его как аргумент методаwrite()
дляFileChannel
- Когда мы закончим писать, мы должны закрыть ресурс
import java.io.*;
import java.nio.*;
public class FileChannelWrite {
public static void main(String[] args) {
File outputFile = new File("hello.txt");
String text = "I love Bangladesh.";
try {
FileOutputStream fos = new FileOutputStream(outputFile);
FileChannel fileChannel = fos.getChannel();
byte[] bytes = text.getBytes();
ByteBuffer buffer = ByteBuffer.wrap(bytes);
fileChannel.write(buffer);
fileChannel.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
}
Написание файла с помощью PrintStream
Мы можем использовать класс PrintStream
для записи файла. Он имеет несколько методов, которые позволяют печатать любые значения типа данных. Метод println()
добавляет новую строку. Когда мы закончим печать, мы должны очистить PrintStream
.
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.time.LocalDate;
public class FileWritingDemo {
public static void main(String[] args) {
String destination = "file1.txt";
try(PrintStream ps = new PrintStream(destination)){
ps.println("Stackoverflow documentation seems fun.");
ps.println();
ps.println("I love Java!");
ps.printf("Today is: %1$tm/%1$td/%1$tY", LocalDate.now());
ps.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Итерация по каталогу, в котором находятся подкаталоги
public void iterate(final String dirPath) throws IOException {
final DirectoryStream<Path> paths = Files.newDirectoryStream(Paths.get(dirPath));
for (final Path path : paths) {
if (Files.isDirectory(path)) {
System.out.println(path.getFileName());
}
}
}
Добавление каталогов
Чтобы создать новый каталог из экземпляра File
вам нужно использовать один из двух методов: mkdirs()
или mkdir()
.
-
mkdir()
- создает каталог с именем этого абстрактного пути. ( источник ) -
mkdirs()
- создает каталог с именем этого абстрактного пути, включая любые необходимые, но несуществующие родительские каталоги. Обратите внимание: если эта операция не удалась, возможно, ей удалось создать некоторые из необходимых родительских каталогов. ( источник )
Примечание: createNewFile()
не создаст новый каталог только для файла.
File singleDir = new File("C:/Users/SomeUser/Desktop/A New Folder/");
File multiDir = new File("C:/Users/SomeUser/Desktop/A New Folder 2/Another Folder/");
// assume that neither "A New Folder" or "A New Folder 2" exist
singleDir.createNewFile(); // will make a new file called "A New Folder.file"
singleDir.mkdir(); // will make the directory
singleDir.mkdirs(); // will make the directory
multiDir.createNewFile(); // will throw a IOException
multiDir.mkdir(); // will not work
multiDir.mkdirs(); // will make the directory
Блокирование или перенаправление стандартного вывода / ошибки
Иногда плохо разработанная сторонняя библиотека будет писать нежелательную диагностику в потоки System.out
или System.err
. Рекомендуемые решения для этого - либо найти лучшую библиотеку, либо (в случае с открытым исходным кодом) исправить эту проблему и внести исправления разработчикам.
Если вышеупомянутые решения не осуществимы, вам следует рассмотреть возможность перенаправления потоков.
Перенаправление в командной строке
В UNIX, Linux или MacOSX система может быть выполнена из оболочки с помощью >
перенаправления. Например:
$ java -jar app.jar arg1 arg2 > /dev/null 2>&1
$ java -jar app.jar arg1 arg2 > out.log 2> error.log
Первый перенаправляет стандартный вывод и стандартную ошибку на «/ dev / null», которая отбрасывает все, что написано в эти потоки. Второй из перенаправляет стандартный вывод на «out.log» и стандартную ошибку на «error.log».
(Для получения дополнительной информации о перенаправлении см. Документацию используемой командной оболочки. Аналогичные рекомендации относятся к Windows.)
Кроме того, вы можете реализовать перенаправление в сценарии оболочки или пакетном файле, который запускает приложение Java.
Перенаправление в приложении Java
Также возможно перенастроить потоки в Java-приложении, используя System.setOut()
и System.setErr()
. Например, следующий фрагмент перенаправляет стандартный вывод и стандартную ошибку на 2 файла журнала:
System.setOut(new PrintStream(new FileOutputStream(new File("out.log"))));
System.setErr(new PrintStream(new FileOutputStream(new File("err.log"))));
Если вы хотите полностью отбросить вывод, вы можете создать выходной поток, который «пишет» на недопустимый дескриптор файла. Это функционально эквивалентно записи в «/ dev / null» в UNIX.
System.setOut(new PrintStream(new FileOutputStream(new FileDescriptor())));
System.setErr(new PrintStream(new FileOutputStream(new FileDescriptor())));
Внимание: будьте осторожны, как вы используете setOut
и setErr
:
- Перенаправление повлияет на всю JVM.
- Делая это, вы убираете способность пользователя перенаправлять потоки из командной строки.
Доступ к содержимому ZIP-файла
API-интерфейс FileSystem Java 7 позволяет читать и добавлять записи из или в Zip-файл с использованием API-интерфейса Java NIO так же, как и в любой другой файловой системе.
FileSystem - это ресурс, который должен быть правильно закрыт после использования, поэтому следует использовать блок try-with-resources.
Чтение из существующего файла
Path pathToZip = Paths.get("path/to/file.zip");
try(FileSystem zipFs = FileSystems.newFileSystem(pathToZip, null)) {
Path root = zipFs.getPath("/");
... //access the content of the zip file same as ordinary files
} catch(IOException ex) {
ex.printStackTrace();
}
Создание нового файла
Map<String, String> env = new HashMap<>();
env.put("create", "true"); //required for creating a new zip file
env.put("encoding", "UTF-8"); //optional: default is UTF-8
URI uri = URI.create("jar:file:/path/to/file.zip");
try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
Path newFile = zipFs.getPath("/newFile.txt");
//writing to file
Files.write(newFile, "Hello world".getBytes());
} catch(IOException ex) {
ex.printStackTrace();
}