My goal
I am trying to write simple objects (SimpleType) into files, so that the files can be loaded later and the objects recreated.
My setting
I am currently working in the NetBeans IDE (JDK8) on a Windows 7 machine. I don't think that should make a difference, though.
This is the type I would like to write into the file:
public class SimpleType implements Serializable {
boolean[] a;
boolean[] b;
}
This is the code I'm trying to get to run:
public class Test {
public static void main(String[] args)
throws IOException, ClassNotFoundException {
String fileName = "test.txt";
SimpleType foo = new SimpleType;
try (ObjectOutputStream out = new ObjectOutputStream(new
BufferedOutputStream(new FileOutputStream(fileName)))) {
out.writeObject(foo);
out.close();
}
}
}
My problem
The code compiles and runs, but always throws a FileNotFoundException:
Exception in thread "main" java.io.FileNotFoundException: test.txt (Access is denied)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
at Test.main(Test.java:33)
My attempts to fix it
According to the documentation, I would expect the file to be created if it doesn't exist already. I've thoroughly read the Javadoc for the method I attempt to use, an excerpt of which I cite here (emphasis mine):
public FileOutputStream(String name) throws FileNotFoundException
[...]
Parameters:
name - the system-dependent filename
Throws:
FileNotFoundException - if the file exists but is a directory rather
than a regular file, does not exist but cannot be created, or cannot
be opened for any other reason
SecurityException - if a security manager exists and its checkWrite
method denies write access to the file.
I am sure that I have read/write permissions in the directory; there is no existing file with the name test.txt so it cannot be locked by another program.
Changing fileName to an absolute path I am sure I can write into doesn't make any difference.
It is reproducible if file is in read-only mode. Can you try like this.
public static void main(String[] args) {
String fileName = "sampleObjectFile.txt";
SampleObject sampleObject = new SampleObject();
File file = new File(fileName);
file.setWritable(true); //make it writable.
try(ObjectOutputStream outputStream = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))){
outputStream.writeObject(sampleObject);
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
If you are writing the file on OS disk you need admin privileges. so avoid writing on OS disk.
Normally this is because you are trying to write on a location not allowed by your FileSystem (for example in Windows7 you cannot write a new file in c:). Try to investigate where the program is trying to write using procmon from Microsoft's SysInternals. Add a new filter (path contains test.txt) and see what happens.
Related
I have my program in a JAR file, and some files in a folder in the same directory. After hours of searching I found some code that allowed me to list the files inside that folder (since File.listFiles() didn't work), but now readObject() gives me IOException. It works fine when I run it from the IDE or with cmd. It only throws the exception when running the JAR via double click.
Here's what I'm doing:
public static Template[] loadTemplates() throws IOException, ClassNotFoundException {
Path dirtemp = Paths.get(path.toString(), TEMPLATE_PATH);
DirectoryStream<Path> dirStream = Files.newDirectoryStream(dirtemp);
ArrayList<File> files = new ArrayList<>();
for (Path entry: dirStream) {
files.add(entry.toFile());
}
if (files.size() != 0) {
ArrayList<Template> templates = new ArrayList<>();
for (File file: files) {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject();
if (object instanceof Template) {
templates.add((Template) object);
}
ois.close();
fis.close();
}
Collections.sort(templates);
return templates.toArray(new Template[0]);
} else return null;
}
TEMPLATE_PATH is just a string that contains the name of the folder with the files.
path is a static variable inside my class that contains the current path to the JAR. I initialize it from the main method, since the location is not intended to change. Here's the code that I used to get it, if relevant:
public static void findJARPath() {
final Class<?> referenceClass = Main.class;
final URL url =
referenceClass.getProtectionDomain().getCodeSource().getLocation();
try {
final File jarPath = new File(url.toURI()).getParentFile();
path = Paths.get(jarPath.toURI());
} catch(final URISyntaxException ignored){}
}
Does anyone know why this happens?
I'm running on Windows but I want this to run on different OS as well. I'd appreciate if you pointed out if any of this code is not portable, too.
Edit:
The stack trace of the exception:
javax.swing.ImageIcon local class incompatible: stream class desc serialVersionUID = -962022720109015502, local class serialVersionUID = 532615968316031794
java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689)
java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1903)
java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1772)
java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2355)
java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2249)
java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2087)
java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
Data.FileManager.loadTemplates(FileManager.java:108)
The code that writes the files:
public static void saveTemplate(Template template) {
new File(TEMPLATE_PATH).mkdir();
String filename = StringUtils.toFilename(template.getName(), "templ");
try {
FileOutputStream fos = new FileOutputStream(TEMPLATE_PATH + filename);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(template);
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Edit: Figured it out. Apparently, for whatever reason, the ImageIcon UID from the image in my template class wouldn't match when running the jar via double click. Wrapping the image into another class with a fixed UID solved it.
Your plan defeats itself, of course: "The same directory as my jar file" would obviously contain..... your jar file.
Which will crash if you attempt to read it with an OIS. Apply some filtering as you dirstream through this directory. Does it have the right extension? Is it an actual file (vs. a directory)?
Also, your code has a memory leak; dirstreams are resources, as is a FileInputStream. You must close these. The only safe way to do so is with try/finally or try-with-resources. Search the web for "Java try with resources" if you're unfamiliar with these techniques.
You've saved a JDK11 ImageIcon, and are trying to deserialize it back on a VM that doesn't have that, because it has a JDK14 ImageIcon or whatnot.
More generally, you can't serialize anything if the intent is to allow it to deserialize on another system unless it is very carefully managed. ImageIcon by intent is not managed like that, therefore, you can't save ImageIcons with OIS and OOS. It looks like you can, but the caveat is: Breaks on different VMs.
You gotta toss all this code out and think of another way to serialize ImageIcon objects. Perhaps save the raw pixels, save it as a PNG, etc.
This doesn't seem to create a file or folder. Why?
import java.io.*;
public class file1
{
public static void main(String[] args)
{
File text1 = new File("C:/text1.txt");
File dir1 = new File("C:/dir");
}
This one below does create a file.
import java.io.*;
public class file3
{
public static void main(String[] args)
{
try
{
FileWriter text1 = new FileWriter("C:/text.txt");
FileWriter dir = new FileWriter("C:/dir");
}
catch(Exception e){}
}
}
However, the directory seems to have a strange unusable icon.
What can I do to create a directory.
What are other simple methods to create files and folders.
Surprisingly, the File class does not represent a file. It actually represents a pathname for a file ... that may or may not exist.
To create a file in Java, you need to open it for output; e.g.
File text1 = new File("C:/text1.txt");
FileOutputStream os = new FileOutputStream(text1); // The file is created
// here ... if it doesn't
// exist already.
// then write to the file and close it.
or you could do this - new FileOutputStream("C:/text1.txt"). In both cases, an existing file will be truncated ... unless you use the FileOutputStream with a boolean parameter that says open for appending.
If you want to create a file without writing any data to it, you could also do this:
File text1 = new File("C:/text1.txt");
text1.createNewFile();
However, that will only create a new file if the file didn't already exist.
To create a directory in Java, use the File.mkdir() or File.mkdirs() methods.
UPDATE
You commented:
I tried File dir = new File("C:/dir1").mkdir(); it says incompatible types.
That is right. The mkdir() method returns a boolean to say whether or not it created the directory. What you need to write is something like this:
File dir = new File("C:/dir1");
if (dir.mkdir()) {
System.out.println("I created it");
}
Always READ THE JAVADOCS before using a method or class you are not familiar with!
A couple more things you need to know:
The best way to deal with the problem of making sure a file gets closed is to do something like this:
try (FileOutputStream os = new FileOutputStream(text1)) {
// now write to it
}
The stream os will be closed automatically when the block exits.
It is usually "bad practice" to catch Exception. It is always "bad practice" to catch Exception and do nothing in the handler. This kind of this hides the evidence of bugs, and makes your code unpredictable and hard to debug.
If you're creating a directory with File, you want this:
new File("C:/dir").mkdirs();
For creating directory you can use :
if(!text1.exists()){
text1.mkdir();
}
and for creating file use:
if(!text1.exists()){
try {
text1.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
In a project I'm working on in Windows 7, using JDK 7u25, I have a class that stores the state for the application. That class has a static save method to save the state to disk. I originally had the following code. (state is a JSONObject and I'm assuming that the output directory hasn't necessarily been created when this function is called.)
public State {
private static String stateFile = "\\state\\state.json";
public static void save() {
try {
File sFile = new File(stateFile);
sFile.mkdirs();
sFile.setWritable(true);
FileWriter file = new FileWriter(sFile);
String str = state.toString(4);
file.write(str);
file.close();
} catch (IOException ex) {
HLogger.log(ex.getMessage());
}
}
}
Whenever I ran this code, it logged an IOException - complaining that access to the state file was denied. I discovered that if I changed the save function (as shown below) it would work exactly as expected.
public static void save() {
try {
File sFile = new File(stateFile);
File path = new File(sFile.getParent());
path.mkdirs();
sFile.setWritable(true);
FileWriter file = new FileWriter(sFile);
String str = state.toString(4);
file.write(str);
file.close();
} catch (IOException ex) {
HLogger.log(ex.getMessage());
}
}
Can anyone explain why it's necessary to create the output directory in a separate file object in order to obtain write permission for the file?
This is not permissions failure but is a misuse of FileWriter.
In the first code snippet a directory named state.json is being created by the call to mkdirs() because it:
Creates the directory named by this abstract pathname, including any necessary but nonexistent parent directories. Note that if this operation fails it may have succeeded in creating some of the necessary parent directories.
and then an attempt to write to the directory using a FileWriter is made, which fails. The following is the throws clause From FileWriter(File):
IOException - if the file exists but is a directory rather than a regular file, does not exist but cannot be created, or cannot be opened for any other reason
The second snippet creates a directory named state (because it is using the parent of \\state\\state.json) and then a file named state.json, and therefore uses FileWriter on a regular file which succeeds.
I have tried creating a file, using the code below:
import java.io.File;
public class DeleteEvidence {
public static void main(String[] args) {
File evidence = new File("cookedBooks.txt");
However, the file cookedBooks.txt does not exist anywhere on my computer. I'm pretty new to this, so I'm having problems understanding other threads about similar problems.
You have successfully created an instance of the class File, which is very different from creating actual files in your hard drive.
Instances of the File class are used to refer to files on the disk. You can use them to many things, for instance:
check if files or directories exist;
create/delete/rename files or directories; and
open "streams" to write data into the files.
To create a file in your hard disk and write some data to it, you could use, for instance, FileOutputStream.
public class AnExample {
public static void main(String... args) throws Throwable {
final File file = new File("file.dat");
try (FileOutputStream fos = new FileOutputStream(file);
DataOutputStream out = new DataOutputStream(fos)) {
out.writeInt(42);
}
}
}
Here, fos in an instance of FileOutputStream, which is an OutputStream that writes all bytes written to it to an underlying file on disk.
Then, I create an instance of DataOutputStream around that FileOutputStream: this way, we can write more complex data types than bytes and byte arrays (which is your only possibility using the FileOutputStream directly).
Finally, four bytes of data are written to the file: the four bytes representing the integer 42. Note that, if you open this file on a text editor, you will see garbage, since the code above did not write the characters '4' and '2'.
Another possibility would have been to use an OutputStreamWriter, which would give you an instance of Writer that can be used to write text (non-binary) files:
public class AnExample {
public static void main(String... args) throws Throwable {
final File file = new File("file.txt");
try (FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter out = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
out.write("You can read this with a text editor.");
}
}
}
Here, you can open the file file.txt on a text editor and read the message written to it.
File evidence = new File(path);
evidence.mkdirs();
evidence.createNewFile();
File is an abstract concept of a file which does not have to exist. Simply creating a File object does not actually create a physical object.
You can do this in (at least) two ways.
Write something to the file (reference by the abstract File object)
Calling File#createNewFile
You can also create temporary files using File#createTempFile but I don't think this is what you are trying to achieve.
You have only created an object which can represent a file. This is just in memory though. If you want to access the file you must us ea FileInputStream or a FileOutputStream. Then it will also be created on the drive (in case of the outputstream).
FileOutputStream fo = new FileOutputStream(new File(oFileName));
fo.write("test".getBytes());
fo.close();
This is just ur creating file object by using this object u need to call one method i.e createFile() method..
So use evidence.createNewFile(); if you are creating just file.
else if u want to create file in any specific location then specify your file name
i.e File evidence=new File("path");
In this case if ur specifying any directoty
String path="abc.txt";
File file = new File(path);
if (file.createNewFile()) {
System.out.println("File is created");
}
else {
System.out.println("File is already created");
}
FileWriter fw = new FileWriter(file, true);
string ab="Hello";
fw.write(ab);
fw.write(summary);
fw.close();
I keep getting a "File not found exception", but I know it's there! File file = new File("C:\\A-small-practice.in"); is able to find the file fine, but when I try to use FileInputStream it returns an exception.
import java.io.*;
public class Solution {
public static void main(String[] args) {
File file = new File("C:\\A-small-practice.in");
System.out.println(file.getAbsolutePath()); //prints C:\A-small-practice.in
FileInputStream fstream = new FileInputStream(file);
}
}
The File has some methods that can help you.
boolean canExecute();
boolean canRead();
boolean canWrite();
boolean exists();
boolean isFile();
boolean isDirectory();
boolean isAbsolute()
For example, you could check for: exists() && isFile() && canRead() and print a better error-message depending on the reason why you cant read the file.
When you write :
File file = new File("C:\\A-small-practice.in");
A file will be made if one dosen't exist, so there will be no reason for
you the get an exception when call file.getAbsolutePath()).
However if the file didn't exist it will throw a file not found exception,
once you try to open an input stream for a non existing file.
So my suggestion is try calling .exsits(). To see if the file do exist.
Also the java documenation for the file not found exception says the following :
"It will also be thrown by these constructors if the file does exist but for some reason is inaccessible".
So perhaps you should share some info on the file itself.