In this article, I want to discuss in great detail how to work with files by using Java.
- File
- Reading and writing content
File
Well, let’s start first with understanding what is it file and file system.
File System
Let’s imagine our machine memory as a big canvas of cells that is able to store some data. Everything we have in our machine is stored there. In order to keep it organized, we have a file system. The file system controls how data is stored. Without it, data would be one large body of data with no way to tell where one piece of data stops and the next starts. So by separating the data and giving them a name(single file) helps us quickly find and work with the data. The file system consists of files and directories(folders). They are organized in a tree structure. There is one root directory from where the whole structure is started. Each file and directory has a unique file path, by this path we can find and work with them.
File
The file is isolated data with a name and unique file path in the file system. The file has a header and content. Inside the header, it will have metadata — data about this file like size, type, how to read, permissions, last modified, etc. The content part will actually have the content of that file.
In Java, files and directories are represented with one File object
Almost any programming language can manipulate(read, write, create, delete) files and directories by using the ready build-in frameworks and classes. However, it’s important to keep in mind that files are just a bunch of data in the memory and they got virtually structured as a file system.
java.io.File class
java.io
package(io — input/output) will have most of the classes we will need to know to work with files in java. The first class we will take a look at is the File class. It represents files and directories in Java. While creating it we have to pass the file path(basically we need to tell which file or directory it should represent as a java object). We cannot read or write data into this file by using only the File object.
Mainly, we can use this object to:
- Get metadata(data about data) about our file. For example, the size, last modified, and other useful data.
- We can create this file/directory if doesn’t exist(or override if it exists)
- We can delete it.
Let’s see the java code. Assume, I have a test.txt
file on my desktop with Hello, World!
content.
- The file class represents files and directories.
- In order to create a File object, we need to path File Path for a file we want to represent as a java object.
- It has many useful methods to gather information about files/directories.
There are two types of file paths:
1. Absolute path that starts from the root of the file system.
For example,/Users/beknazarsuranchiyev/Desktop/test.txt
/
is root for Mac and for Windows it can beC
driver2. Relative path that ‘compiles’ from the place the code is running.
For example,src/test/myFile.txt
— — — — — — — — — — — — — — — — — — — — — — — — — —
Sometimes you will see\\
and/
delimiters in the file path.
\
— is for Windows operation system. Since\
is a special character in Java, we need to escape it with another\
so that why we have\\
/
— is for the Linux-based operating system(Mac as well uses it).
I recomend always use/
linx-based delimeter(it will work if you run code in wndows machines as well).
If a file or directory does not exist in the specified path, we can create them.
- we can create an empty file by using
createNewFile()
method. - it does throw an unchecked exception so we need to handle it by declaring or catching(in this example just declaring).
- In this example, we are creating our file here: /Users/beknazarsuranchiyev/Desktop/apple.txt
if Desktop directory wouldn’t exist, the code would fail to create our apple.txt file. SocreateNewFile()
is not able to create underline directories if they don’t exist. We will need to create them separately.
Let’s create directories
mkdir()
is a method to create a directory(taking name from Linux)- if a directory is not created it will not throw an exception but will return false(one reason folder cannot be created is permissions)
- There is
mkdirs()
that can create non-existing parent directories.
We can delete files and folders by using delete()
command.
I want to discuss more on permissions
- We can find out read access by
carRead()
method. - We can find out write access by
canWrite()
method. - We can find out the execute access by
canExecute()
method.
Ok, few more useful pieces of information:
- Find out which ID is running the code:
System.out.println(System.getProperty("user.name"));
- If you need more info about files/directories permissions, you might try to run
Linux
commands from Java code. This is the last option to go.
Reading and writing content
In general, there are two ways of working with reading and writing files in Java.
- InputStream and OutputStream.
The Stream classes are used for inputting and outputting all types of binary or byte data. - Reader and Writer.
The Reader and Writer classes are used for inputting and outputting characters and strings. Basically, text files.
Let’s talk about Streams
Both InputStream/OutoutStream and Reader/Writer use streams in the background(Even Reader/Writer does not have a stream in their name). The main idea of the stream is to read/write piece by piece. For example, we want to read the content of a huge(100 GB let’s say) text file and let’s say count the number of letters. Reading and loading all content into memory(RAM memory) wouldn’t be the best option, memory can simply get overflowed. However, reading data piece by piece will not overflow the memory of course if we are not storing everything in the memory as well.
Let’s see how we can read file content using InputStream
- It will print
Hello, World!
if my file under/Users/beknazarsuranchiyev/Desktop/test.txt
will haveHello, World!
content. while((b = in.read()) != -1) {content.append((char)b);}
this is the most important part of the code.in.read()
will read the piece of the content and return it asint
. When it is used next time, it will read the next piece and so on. When it will return-1
it means it reached the end of the file content. First, we are assigning the value ofin.read()
method to ourb
variable then we are checking if it’s-1
or not. If it’s-1
, we are exiting from the loop and if it’s not we are putting value into our SpringBuilder.- We always need to close our resources(files, database connections). In this case, we are closing it in
finally
block because it always runs(does not matter if an exception occurs or not).in.close()
also throws checked exception so we are handling it there as well. - In this example, we are reading each byte separately, but there is an option to read multiple bytes at the same time. Reading multiple bytes at the same time of text files requires some extra code to convert bytes into String representation(better to use reader/writer classes).
- The above code is a little old version of using exceptions and closing. We will see a better way of doing it.
Let’s see another example:
This is code does a lot more, but it looks shorter and nicer. It will make a copy of sourceFile
to the place with a name specified in targetFile
.
try() {}
try with resources. The main idea is that it will close the resources automatically in the end so we don’t have to usefinally
block and close them manually. You can see, we opened two resources there and we don’t have to worry about closing them. The try with resources will handle it. If you want to create your custom class that will work with it, you will need to implementCloseable
interface.byte[] buffer = new byte[1024];
we are passing it intoread()
method. We are specifying the number of bytes to read as one piece. It will improve the efficiency of overall reading and writing.- The last thing to note is the way we write into the file.
new FileOutputStream(targetFile)
is responsible to write content into the file(if the file does not exist it will create one).out.write(buffer, 0, b);
is used to write content into the file. 'Inputs'
is for reading and'Outputs'
is for writing.
Now, let’s talk about Readers and Writers
They also use streams only difference is they are made specifically to work with text files (characters, strings).
- As you can see it has a similar concept with Streams.
Buffers(high-level classes)
The buffer classes exist for Streams and Reader/Writers as well. They are wrapper classes that provide more abstract methods to work with files in an easier way. There are two types of IO classes that can actually read and write.
High-level and low-level. So far we have been working only with low-level classes. As we already said high-level classes provide additional methods to work with file data in higher-level for example to read the whole lines.
- You can see as
new BufferedReader(new FileReader(file))
is wrapping low-level reader. This is the way we use high-level IO classes by wrapping the low-level IO classes.
- in this example, we have a method that will read text file content and return it as String.
- Notice, we have used
stream
(not IO streams) of java here to make code shorter.
The same idea of buffer classes we have ‘Stream’ classes. It’s always recommended to use buffer high-level classes.
Summary
We use File
class to represent files and directories in java. We can get information about this file. We can create new files/directories or we can delete them. However, we cannot use it to read or write content.
In order to read and write files Java utilizes Streams
. The main idea is to read/write the content of the file piece by piece.
There are two types of IO classes to read and write the content of the class.
- Input/Output streams. They read and write all types of data. It works at the binary level.
- Readers/Writers. They work for text content files.
Buffer or high-level are classes that are wrapper classes of low-level IO classes. Buffer classes will prove additional methods to work with file content at a higher level. It is always good practice to use buffered classes unless you are doing something specific and need low-level access to content.
That’s all for today, have a good one!
Please take my Java Course for video lectures.This article is part of the series of articles to learn Java programming language from Tech Lead Academy:Introduction to programming
OS, File, and File System
Working with terminal
Welcome to Java Programming Language
Variables and Primitives in Java
Convert String to numeric data type
Input from the terminal in Java
Methods with Java
Java Math Operators and special operators
Conditional branching in Java
Switch statement in Java
Ternary operator in Java
Enum in Java
String class and its methods in Java
Loops in Java
Access modifiers in Java
Static keyword in Java
The final keyword in Java
Class and Object in Java
Object-Oriented Programming in Java
OOP: Encapsulation in Java
OOP: Inheritance in Java
OOP: Abstraction in Java
OOP: Polymorphism in Java
The method Overriding vs Overloading in Java
Array in Java
Data Structures with Java
Collection framework in Java
ArrayList in Java
Set in Java
Map in Java
Date and Time in Java
Exception in Java
How to work with files in Java
Design Patterns
Generics in Java
Multithreading in java
Annotations in Java
Reflection in Java
Reflection & Annotations - The Powerful Combination
Run terminal commands from Java
Lambda in Java
Unit Testing in Java
Big O Notation for coding interviews
Top Java coding interview questions for SDET