To make a file read-only in Java, we call file.setReadOnly() on a java.io.File, or, on Linux and macOS, remove the write bits with Files.setPosixFilePermissions(). On Windows, the same setReadOnly() call sets the DOS read-only attribute, which we can also set with Files.setAttribute(path, “dos:readonly”, true).
We mark files read-only to stop our own app or a careless script from changing them, for example an invoice PDF that was already sent to a customer, an exported audit log, a signed contract or a configuration file that only the deployment should change.
The following example makes a configuration file read-only, checks its permissions and makes it writable again.
Path dir = Files.createTempDirectory("config");
Path appYml = Files.writeString(dir.resolve("app.yml"), "port: 8080");
boolean done = appYml.toFile().setReadOnly(); // true
String perms = PosixFilePermissions.toString(Files.getPosixFilePermissions(appYml)); // "r--r--r--"
boolean back = appYml.toFile().setWritable(true); // true, owner can write again
Notice that setReadOnly() returns a boolean and does not throw on failure, so we always check the result. We look at what read-only means on each operating system, the difference between setReadOnly() and setWritable(false), POSIX permissions, the DOS attribute, checking the state and the limits of read-only protection.
1. What Read-Only Means on Each Operating System
Linux and macOS store read, write and execute permissions for the owner, the group and everybody else, written as rw-r–r–. A file is read-only for a user when that user’s write bit is missing. Windows has no such bits for this purpose, and it keeps a single read-only attribute on the file instead.

The two models behave differently in the cases that surprise people most.
| Action on a read-only file | Linux and macOS (r–r–r–) | Windows (read-only attribute) |
|---|---|---|
| Read the content | Allowed | Allowed |
| Write or append | AccessDeniedException | AccessDeniedException |
| Delete the file | Allowed when the folder is writable | AccessDeniedException |
| Write as root or administrator | Root writes anyway | Blocked until the attribute is cleared |
| Change it back | The owner or root can | Anyone with write access to the file’s attributes can |
2. Make a File Read-Only With File.setReadOnly()
The method setReadOnly() removes write access for everybody, so on Linux it clears the write bit of the owner, the group and others. The method setWritable(false) clears only the owner’s write bit, and a group that had write access keeps it.
Path shared = Files.createTempDirectory("shared");
Path a = Files.writeString(shared.resolve("a.txt"), "x");
Path b = Files.writeString(shared.resolve("b.txt"), "x");
Path aPerms = Files.setPosixFilePermissions(a, PosixFilePermissions.fromString("rw-rw-r--")); // group can write
Path bPerms = Files.setPosixFilePermissions(b, PosixFilePermissions.fromString("rw-rw-r--")); // group can write
boolean aDone = a.toFile().setReadOnly(); // true
boolean bDone = b.toFile().setWritable(false); // true
String aAfter = PosixFilePermissions.toString(Files.getPosixFilePermissions(a)); // "r--r--r--"
String bAfter = PosixFilePermissions.toString(Files.getPosixFilePermissions(b)); // "r--rw-r--"
Use setReadOnly() when the file must be read-only for everyone, because setWritable(false) leaves group and others write access in place. The overload setWritable(false, false) clears the write bit for all three classes, which gives the same result as setReadOnly() on Linux.
Both methods return false when they cannot change the file, for example when it does not exist or belongs to another user. They don’t throw, so a missing file goes unnoticed unless we check the result.
Path dir = Files.createTempDirectory("invoices");
File missing = dir.resolve("inv-7.pdf").toFile();
boolean changed = missing.setReadOnly(); // false, no such file
3. POSIX Permissions With Files.setPosixFilePermissions()
On Linux and macOS, Files.setPosixFilePermissions() gives exact control and throws an IOException that names the problem. To make a file read-only without touching the read and execute bits, we read the current set, remove the three write permissions and write the set back.
static void removeWriteAccess(Path file) throws IOException {
Set<PosixFilePermission> perms = new HashSet<>(Files.getPosixFilePermissions(file));
perms.removeAll(Set.of(PosixFilePermission.OWNER_WRITE,
PosixFilePermission.GROUP_WRITE, PosixFilePermission.OTHERS_WRITE));
Files.setPosixFilePermissions(file, perms);
}
Path bin = Files.createTempDirectory("bin");
Path script = Files.writeString(bin.resolve("deploy.sh"), "echo ok");
Path exec = Files.setPosixFilePermissions(script, PosixFilePermissions.fromString("rwxr-xr-x")); // executable
removeWriteAccess(script);
String scriptPerms = PosixFilePermissions.toString(Files.getPosixFilePermissions(script)); // "r-xr-xr-x"
Say a release pipeline copies application.yml to a server. The app reads it at startup but should never edit it, so the pipeline sets r–r—–. The app user, in the owning group, can read the file, other users can’t see its content, and nobody except root can modify it by accident.
Path release = Files.createTempDirectory("release");
Path yml = Files.writeString(release.resolve("application.yml"), "db: prod");
Path locked = Files.setPosixFilePermissions(yml, PosixFilePermissions.fromString("r--r-----"));
String ymlPerms = PosixFilePermissions.toString(Files.getPosixFilePermissions(locked)); // "r--r-----"
We can also create a file read-only from the start by passing the permissions to Files.createFile(), as shown in creating a new file. On Windows, the POSIX methods throw UnsupportedOperationException.
4. The DOS Read-Only Attribute
On Windows, the read-only flag is part of the DosFileAttributeView. We set it by attribute name with Files.setAttribute() or through the view, and read it back with DosFileAttributes.isReadOnly().
Path docs = Files.createTempDirectory("docs");
Path contract = Files.writeString(docs.resolve("contract.pdf"), "x");
Path flagged = Files.setAttribute(contract, "dos:readonly", true); // sets the flag
boolean readOnly = Files.readAttributes(contract, DosFileAttributes.class).isReadOnly(); // true
Linux also supports the dos view, but there the JDK stores the flag in an extended attribute of the file. The POSIX permissions stay as they were, so the file remains writable. Cross-platform code therefore picks the mechanism that the file system enforces.
static void makeReadOnly(Path file) throws IOException {
if (file.getFileSystem().supportedFileAttributeViews().contains("posix")) {
removeWriteAccess(file);
} else {
Files.setAttribute(file, "dos:readonly", true);
}
}
Path out = Files.createTempDirectory("out");
Path audit = Files.writeString(out.resolve("audit.log"), "x");
makeReadOnly(audit);
String auditPerms = PosixFilePermissions.toString(Files.getPosixFilePermissions(audit)); // "r--r--r--"
5. Making a File Writable Again
Every method has a counterpart that restores write access. Code that updates a protected file, for example a nightly job that appends to a locked audit log, clears the flag, writes and sets it again in a finally block.
Path dir = Files.createTempDirectory("logs");
Path log = Files.writeString(dir.resolve("audit.log"), "x");
boolean locked = log.toFile().setReadOnly(); // true
boolean ownerOnly = log.toFile().setWritable(true); // true, owner may write
String ownerPerms = PosixFilePermissions.toString(Files.getPosixFilePermissions(log)); // "rw-r--r--"
boolean everyone = log.toFile().setWritable(true, false); // true, all may write
String allPerms = PosixFilePermissions.toString(Files.getPosixFilePermissions(log)); // "rw-rw-rw-"
With POSIX permissions, we add OWNER_WRITE back to the set, and with the DOS attribute we call Files.setAttribute(path, “dos:readonly”, false).
6. Checking Whether a File Is Read-Only
The methods File.canWrite() and Files.isWritable() answer whether the current process may write the file, which is not the same as whether the file is marked read-only. A process running as root, as many containers do, gets true even for a file with r–r–r–.
To check the file’s own setting, we look at the permissions or the DOS attribute.
Path dir = Files.createTempDirectory("check");
Path report = Files.writeString(dir.resolve("report.pdf"), "x");
boolean marked = report.toFile().setReadOnly(); // true
Set<PosixFilePermission> perms = Files.getPosixFilePermissions(report);
boolean noWriteBits = !perms.contains(PosixFilePermission.OWNER_WRITE)
&& !perms.contains(PosixFilePermission.GROUP_WRITE)
&& !perms.contains(PosixFilePermission.OTHERS_WRITE);
boolean readOnlyForAll = noWriteBits; // true
For a normal user, Files.isWritable(report) returns false after setReadOnly(), and that is the right check before an optional write. The same caution as in checking if a file exists applies, so we still handle AccessDeniedException on the write itself.
7. What Read-Only Does Not Protect
Read-only is a guard against mistakes, not a security boundary. Root on Linux and any user with rights to change the attributes on Windows can write the file or restore write access. On Linux, deleting or renaming a file needs write access to the folder that contains it, so a read-only file in a writable folder can still be deleted.
Path tmp = Files.createTempDirectory("tmp");
Path note = Files.writeString(tmp.resolve("note.txt"), "keep me");
boolean ro = note.toFile().setReadOnly(); // true
Files.delete(note); // works on Linux, folder is writable
boolean gone = Files.notExists(note); // true
To protect files against deletion on Linux, we remove write access from the folder as well, or move the file to storage the app cannot write, such as a separate volume mounted read-only. To delete a read-only file on Windows, we clear the attribute with Files.setAttribute(path, “dos:readonly”, false) first, and the same applies to every read-only file inside a recursive directory delete.
8. Read-Only File FAQs
A read-only flag behaves differently on folders, fails without an exception and is often confused with opening a file for reading, which is what most of these questions are about.
8.1. Can we make a directory read-only in Java?
Yes, the same methods work on folders. On Linux, a folder without write bits blocks creating, renaming and deleting entries inside it for normal users, while the files inside keep their own permissions. On Windows, the read-only attribute on a folder does not stop changes to its files.
8.2. Why does setReadOnly() return false?
The file does not exist, the process is not the owner, or the file system does not support the change. The method gives no reason, so we call Files.setPosixFilePermissions() or Files.setAttribute() when we need an exception that names the cause.
8.3. How do we open a file in read-only mode instead?
That is a different feature. Files.newInputStream(), Files.newBufferedReader() and Files.readString() open a file for reading only, so our code cannot write through that handle, but the file itself stays writable for others. See reading a file to a string.
8.4. How do we make a file read-only for other users only?
We remove only the group and others write bits and keep the owner’s bit.
Path dir = Files.createTempDirectory("team");
Path plan = Files.writeString(dir.resolve("plan.md"), "x");
Path set = Files.setPosixFilePermissions(plan, PosixFilePermissions.fromString("rw-r--r--")); // owner keeps write
String planPerms = PosixFilePermissions.toString(Files.getPosixFilePermissions(plan)); // "rw-r--r--"
9. Conclusion
File.setReadOnly() makes a file read-only for everyone on every platform, while setWritable(false) affects only the owner. On Linux and macOS, Files.setPosixFilePermissions() gives exact control and reports failures as exceptions, and on Windows the dos:readonly attribute is the flag the system enforces.
We check the return value of the File methods, check the permissions rather than canWrite() when the process may run as root, and remember that read-only does not stop root, nor deletion from a writable folder on Linux. For copying and moving files, start from the Java IO tutorial.
10. References
- File.setReadOnly() Javadoc
- Files.setPosixFilePermissions() Javadoc
- PosixFilePermissions Javadoc
- DosFileAttributeView Javadoc
- Oracle Java Tutorial, Managing Metadata
Happy Learning !!