I have a problem not to solve by myself.
I'm a biginner in JAVA.
I don't know solution about this problem. But I think that I know when this problem occurs.
So, I aleady have solution about this problem. But I want another solution because my solution has another problem too. I have to reduce the process time.
String intDir="C:\\RNE_IN";
while(true) {
File interfaceDirectory = new File(intDir);
String[] arrayfiles = interfaceDirectory.list(new FBMFileFilter());
for(String f : arrayfiles){
String filename = String.format("%1$s%2$s%3$s", intDir,File.separator,f);
File file = new File(filename);
FileInputStream stream = null;
System.out.println(file.canExecute()); // true
System.out.println(file.canRead()); // true
System.out.println(file.exists()); // true
System.out.println(file.isFile()); // true
System.out.println(file.length()); // call full bytes of file
// I can control NPE with this Thread sleep Time.
Thread.sleep(1);
// It occurs when Stream is constructed in the below.
stream = new FileInputStream(file);
FBMDeviceOnlyParser onlyparser = new FBMDeviceOnlyParser();
onlyparser.ParseDeviceNameOnly(stream);
String onlydevice = onlyparser.getDeviceName();
String onlystepseq = onlyparser.getStepSeq();
}
}
In above snippet, I think file has no problem.
file state is always true and file.length is full byte regardless Exception.
But, while infinite Loop, If I copy & paste from another Directory to the intDir , "NullPointerException" occurs.
When Thread.sleep(time) is over 1000ms, NPE doesn't occur.
I want to delete "Thread.sleep()" code because of process time.
If there are files in the intDir aleady before program start, Program has No problem (it doesn't occur NPE)
I want to check file or FileInputStream state not to occur NPE.
Thank you for your concern.
Your question is hard to understand, but I can tell you for a fact that it is impossible to get:
java.lang.NullPointerException at Apeiron.MainEntry.main(MainEntry.java:179) Exception in thread "main"
java.lang.NullPointerException at Apeiron.MainEntry.main(MainEntry.java:260)
if line 179 is this line:
stream = new FileInputStream(file);
One of the following must be:
you have given us an incomplete stack trace, or
you've told us the incorrect location of the exception, or
you are not actually executing that code at all; e.g. you've not rebuilt the code properly after changing it.
You probably run out of file handles sooner or later. Close the FileInputstream when you are finished with it.
Besides that, explain what you really want to do with your code (instead of driving CPU usage to the top).
How about this:
String intDir="C:\\RNE_IN";
File interfaceDirectory = new File(intDir);
while(true) {
for(File file : interfaceDirectory.listFiles(new FBMFileFilter())) {
System.out.println(file.canExecute()); // true
System.out.println(file.canRead()); // true
System.out.println(file.exists()); // true
System.out.println(file.isFile()); // true
System.out.println(file.length()); // call full bytes of file
final FileInputStream stream = new FileInputStream(file);
try {
FBMDeviceOnlyParser onlyparser = new FBMDeviceOnlyParser();
onlyparser.ParseDeviceNameOnly(stream);
String onlydevice = onlyparser.getDeviceName();
String onlystepseq = onlyparser.getStepSeq();
} finally {
stream.close();
}
}
}
I did a couple of things --
1. got rid of unnecessary file name generation
2. put a try finally to release file handle resources
BTW, my guess is that your sleep allowed finalizers to run.
Related
I am working on a utility that zips up a number of files (for diagnostics purposes). At it's core, it uses the following function:
private void write(ZipOutputStream zipStream, String entryPath, ByteSource content) throws IOException {
try (InputStream contentStream = content.openStream()) {
zipStream.putNextEntry(new ZipEntry(entryPath));
ByteStreams.copy(contentStream, zipStream);
zipStream.closeEntry();
}
}
But one of the files I want to read is a log file that another application runs and locks. Because that file is locked, I get an IO exception.
<ERROR>java.io.IOException: The process cannot access the file because another process has locked a portion of the file
at java.base/java.io.FileInputStream.readBytes(Native Method)
at java.base/java.io.FileInputStream.read(FileInputStream.java:257)
at com.google.common.io.ByteStreams.copy(ByteStreams.java:112)
If I am willing to accept that I might get some garbage because of conflicts between my reads and the other application's writes, what is the best/easiest way to work around this? Is there a file reader that ignores locks or perhaps only reads all the unlocked sections only?
Update -- To clarify, I am looking to read a log file, or as much of it as possible. So, I could just start reading the file, wait until I get a block I can't read, catch the error, append a file end and go. Notepad++ and other programs can read files that are partially locked. I'm just looking for a way to do that without re-inventing the ByteStreams.copy function to create a "Copy as much as I can" function.
I should have perhaps asked "How to read all the unlocked parts of a log file" and I will update the title.
One possible answer (which I don't like) is to create a method almost identical to ByteStreams.copy(), which I call "copyUntilLock" which catches any IOException, then it checks to see if the exception is a because another process has locked a portion of the file.
If that is the case, then simply stop writing and return the number of bytes so far. If its some other exception go ahead and throw it. (You could also write a note to the stream like "READING FAILED DUE TO LOCK").
Still looking for a better answer. Code included below.
private static long copyUntilLock (InputStream from, OutputStream to) throws IOException {
checkNotNull(from);
checkNotNull(to);
byte[] buf = createBuffer();
long total = 0;
try {
while (true) {
int r = from.read(buf);
if (r == -1) {
break;
}
to.write(buf, 0, r);
total += r;
}
return total;
} catch (IOException iox) {
if (iox.getMessage() != null && iox.getMessage().contains("another process has locked a portion of the file")) {
return total;
} else {
throw iox;
}
}
}
I am new to Java and I need help.
When I reopen GUI, it doesn't shows what has been saved into the file, which was serialization. The file is saving successful, but when I close and reopen and run the application it doesn't show on JList, what was saved into this file.
try
{
FileInputStream jos = new FileInputStream("jokam.ser");
GZIPInputStream gis = new GZIPInputStream(jos);
ObjectInputStream hehe = new ObjectInputStream(gis);
v1= (Vector<Vector>)hehe.readObject();
Vpredmeti.addAll((Collection<? extends Predmet>)v1.get(0));
Vvlak.addAll((Collection<? extends Vlak>)v1.get(1));
jos.close();
hehe.close();
gis.close();
v1.addAll(0, v1);
for(Predmet pr : predmetAR){
System.out.println(pr);
}
}
catch (Exception e)
{
}
}
These Vectors are before try code.
Vector <Predmet> Vpredmeti = new Vector (predmetAR);
Vector <Vlak> Vvlak= new Vector();
Vector <Vector> v1 = new Vector<>();
This is where I add to JList.
private void DodajPredmetMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
// DefaultListModel list = new DefaultListModel();
String praznoPolje=ImePredmeta.getText();
String drugoPraznoPolje=ZnacilnostPredmeta.getText();
int tretjoPraznoPolje = (int)ComboBoxZabojnika.getSelectedIndex();
Predmet novPredmet = new Predmet();
novPredmet.ime = ImePredmeta.getText();
novPredmet.znacilnosti = drugoPraznoPolje;
novPredmet.tipZabojnika=tretjoPraznoPolje;
//list.addElement(novPredmet);
predmetAR.add(novPredmet);
Save code
Vector<Predmet> Vpredmet = new Vector<>(predmetAR);
Vector<Vlak> Vvlak = new Vector<>(vlakAR);
Vector<Vector> v = new Vector<>();
v.add(0,Vpredmet);
v.add(1,Vvlak);
try
{
FileOutputStream fos = new FileOutputStream("jokam.ser");
GZIPOutputStream gos = new GZIPOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(gos);
oos.writeObject(v);
gos.close();
fos.close();
oos.close();
}
catch(Exception e)
{
}
}
Those exceptions you noted are almost definitely problems where a stream was closed early, either on the write part or the read part. It's also indicative of a layering problem with the streams, but I don't see that here.
To first step in solving these problems is making sure all the data is written before the stream is closed, and in the proper order. I usually flush() the highest level stream before closing it or underlying parts. flush() the highest level OutputStream (here, the ObjectOutputStream), and it will flush all the underlying streams (here the GZIPOutputStream and FileOutputStream). Technically close() also flush()es the stream so this may not be necessary.
Also, make sure to close() streams in the correct order. Same as flush(), close the higher level stream and the underlying streams get close()d (and flush()ed) automatically.
The code you already have close()es the GZIPOutputStream first, which precludes the closing bits of the ObjectOutputStream. Later, the ObjectOutputStream is close()d which will try to write those bits but the underlying stream has already been closed so, so an IOException is thrown.
When writing, I suggest trying just:
objectOutputStream.close();
As for the reading, just this should be good:
objectInputStream.close()
As I mentioned in the comments, you should close() in a finally block so that any Exception thrown in the try block still results in the close() being called. Be aware that close() can also throw an Exception ;)
To investigate this on your own, I suggest looking into the source code of all these streams to see what's happening inside. The JDK includes an optional jdk/lib/src.zip, which most IDE's will let you jump into. Try 'go to definition' on your objectOutputStream.close() and you should see the source code.
I'm facing a problem that i really don't understand.
I designed my program to read info from files and then generate reports about it.
At the first time, I open all the files that I need:
clientesarq = new File(args[1]);
fornecedoresarq = new File(args[3]);
produtosarq = new File(args[5]);
then I use a java.util.Scanner to loop through them:
leitor = new Scanner(clientesarq);
leitor.nextLine();
/* leitura e armazenamento dos clientes em mapa */
while(leitor.hasNextLine()) {
Cliente c = pd.novoCliente(leitor);
clientes.addCliente(c);
}
leitor = new Scanner(fornecedoresarq);
leitor.nextLine();
/* leitura e arazenaento dos fornecedores em mapa */
while(leitor.hasNextLine()) {
Fornecedor f = pd.novoFornecedor(leitor);
fornecedores.addFornecedor(f);
}
when my program reaches this part of the code, the JVM throws to me NoSuchElementException.
leitor = new Scanner(produtosarq);
leitor.nextLine(); /* EXCEPTION HERE */
/* leitura e armazenamento dos produtos em mapa */
while(leitor.hasNextLine()) {
Produto p = pd.novoProduto(leitor);
produtos.addProduto(p);
}
I really want to know why the hell I am getting this excpetion, as you can see, the code is exactly the same as the other ones. Any?
You can get all needed files here: https://www.dropbox.com/sh/c48roudfwuj7qzu/AAAMn_OFGXJFHEjVJyZ7piCPa
Use UTF-8 character set to read from file which is able to represent every character in Unicode Format.
Here it will convert Bytes from the file into characters using the specified charset(Here UTF-8) and will make it readable for Scanner I guess.
Scanner input = new Scanner(new File("filename"),"UTF-8");
Specifying the charset did not fix the issue for me. This post is comment-like as I have not fully discovered the issue, but I am making an attempt at explaining the why portion of the question with what I have found thus far.
I found another post with the same problem as a secondary resource. In both cases, the first line of the files ends with ASCII character 13 carriage return which I would have thought should be picked up by the Scanner as a line separator. As a sanity check, I performed a BufferedReader readLine() and it works fine. Digging deeper, I cloned the source of Scanner and wound up on readInput line 849 : n = source.read(buf);.
After determining the type of source was sun.nio.cs.StreamDecoder, I cloned the class and investigated readImpl. In both cases, line 324 int n = readBytes(); reads the entire file into the buffer hitting the continue and coming back around to line 316 CoderResult cr = decoder.decode(bb, cb, eof); At this point cr is wrapping a MalformedInputException which gets consumed by Scanner catch (IOException ioe).
Since I was able to reproduce this issue in my cloned source, I printed the stacktrace:
java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
at javaapplication1.StreamDecoder.implRead(StreamDecoder.java:349)
at javaapplication1.StreamDecoder.read(StreamDecoder.java:188)
at java.io.Reader.read(Reader.java:100)
at javaapplication1.MyScanner.readInput(MyScanner.java:844)
at javaapplication1.MyScanner.findWithinHorizon(MyScanner.java:1789)
at javaapplication1.MyScanner.nextLine(MyScanner.java:1629)
The decoder at runtime is sun.nio.cs.UTF_8. I've stopped digging at this point as it is way into the AM hours, I may edit in further findings.
The main question now is why the final single character of input kills the decoder.
Just a guess but maybe the file you are trying to read doesnt have any information. Always check if it has a next line before getting that next line.
if(scanner.hasNextLine()){
String line = scanner.nextLine();
}
The filesystem AirportHDD is mounted (AFP) from the beginning and the file exists when I start this little program.
I tried to figure out the whole day why the following is not working, but couldnt find any solution:
public static void main(String[] arguments)
{
while(1==1)
{
File f=new File(
"/Volumes/AirportHDD/test/lock.csv");
System.out.println(f.exists());
AmySystem.sleep(100);
}
}
the output is:
true, true, ...
as soon as I remove the file from a different computer (AirportHDD is a mounted harddisk over network) then the output keeps saying:
true, true, ...
when I open the finder and goto this directory the output changes to: false, false, ...
when the file is added again (via another pc) the output is still:
false, false, ...
but if you open the finder again and click on the directory and finder shows the existing file, the output changes suddenly to: false, true, true, true, ...
NOTE:
also all other file operations like opening for read are failing as long as java 'thinks' the file is not there
if the program itself is creating and deleting the files then problem is not occurring
just found out while testing that with samba sharing everything is ok, but with AFP it just wont work
is there a way to tell java to do the same thing as finder, like a refresh, or do not try to cache, whatever?
I think you might be looking for the WatchService. Oracle was also kind enough to provide a tutorial.
Because the longevity of these links aren't guaranteed, I'll edit in an example code in a couple of minutes. I just wanted to let you know I think I found something in case you want to start looking at it for yourself.
UPDATE
Following the linked tutorial, I came up with code like this. I'm not sure it'll work (don't have time to test it), but it might be enough to get you started. The WatchService also has a take() method that will wait for events, which means you could potentially assume the file's existence (or lack thereof) based on the last output you gave. That will really depend on what this program will be interacting with.
If this works, good. If not, maybe we can figure out how to fix it based on whatever errors you're getting. Or maybe someone else will come along and give a better version of this code (or better option altogether) if they're more acquainted with this than I am.
public static void main(String[] arguments) {
Path path = Paths.get("/Volumes/AirportHDD/test/lock.csv");
WatchService watcher = FileSystems.getDefault().newWatchService();
WatchKey key = null;
try {
key = path.register(watcher,
ENTRY_CREATE,
ENTRY_DELETE);
} catch (IOException x) {
System.err.println(x);
}
while(true) {//I tend to favor this infinite loop, but that's just preference.
key = watcher.poll();
if(key != null) {
for (WatchEvent<?> event: key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == OVERFLOW || kind == ENTRY_DELETE) {
System.out.println(false);
}
else if (kind == ENTRY_CREATE) {
System.out.println(true);
}
}//for(all events)
}//if(file event occured)
else {
File f=new File(path);
System.out.println(f.exists());
}//else(no file event occured)
AmySystem.sleep(100);
}//while(true)
}//main() method
Here is a JUnit test that shows the problem
The problem still happens using Samba on OSX Mavericks. A possible reason
is explaned by the statement in:
http://appleinsider.com/articles/13/06/11/apple-shifts-from-afp-file-sharing-to-smb2-in-os-x-109-mavericks
It aggressively caches file and folder properties and uses opportunistic locking to enable better caching of data.
Please find below a checkFile that will actually attempt to read a few bytes and forcing a true file access to avoid the caching misbehaviour ...
JUnit test:
/**
* test file exists function on Network drive
* #throws Exception
*/
#Test
public void testFileExistsOnNetworkDrive() throws Exception {
String testFileName="/Volumes/bitplan/tmp/testFileExists.txt";
File testFile=new File(testFileName);
testFile.delete();
for (int i=0;i<10;i++) {
Thread.sleep(50);
System.out.println(""+i+":"+OCRJob.checkExists(testFile));
switch (i) {
case 3:
// FileUtils.writeStringToFile(testFile, "here we go");
Runtime.getRuntime().exec("/usr/bin/ssh phobos /usr/bin/touch "+testFileName);
break;
}
}
}
checkExists source code:
/**
* check if the given file exists
* #param f
* #return true if file exists
*/
public static boolean checkExists(File f) {
try {
byte[] buffer = new byte[4];
InputStream is = new FileInputStream(f);
if (is.read(buffer) != buffer.length) {
// do something
}
is.close();
return true;
} catch (java.io.IOException fnfe) {
}
return false;
}
The problem is the network file system AFP. With the use of SAMBA everything works like expected.
Maybe the OS returns the wrong file info in OSX with the use of AFP in these scenarios.
I'm completely new to programming, so I'm having a difficult time resolving my own errors. Someone advised me to try it on this website, so I thought why not give it a shot.
The other posts that I found regarding this error didn't seem very relevant: most were people advising to close the input stream, but my code already does that.
What I want it to do: Write a Photo object called "photo" to a file called "test.ser". Then read the file "test.ser" AND return the path of the object ("photo") in "test.ser" back to me.
What it actually does: Writes a Photo object called "photo" to "test.ser". Reads "test.ser", returns an EOFException and no path.
Returning the path isn't actually very important, as long as it returns something of value to me. But I am getting the same error when I use "System.out.println(photo)" or "photo.getId()".
I'm not very sure what I need to paste here, so I will post the two try/catch-es that I use for serializing and deserializing the object:
Serializing object:
File test = new File("path.../something.ser");
Photo photo = new Photo(2, "..\\images\\2.jpg", getImage("..\\images\\2.jpg"));
try {
FileOutputStream fos = new FileOutputStream(test);
ObjectOutputStream out = new ObjectOutputStream(fos);
if (!test.exists()) {
test.createNewFile();
}
out.writeObject(photo);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
Deserializing object:
try {
FileInputStream fis = new FileInputStream(test);
ObjectInputStream in = new ObjectInputStream(fis);
in.readObject();
photo = (Photo)in.readObject();
photo.getPath();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
And the error:
run:
null
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2571)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1315)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at view.Main.<init>(Main.java:103)
//103 is the line that casts the input object to a Photo object.
BUILD SUCCESSFUL (total time: 1 second)
From what I unstander the error occurs when I am trying to type cast the object - that I receive through the method readObject - to a "photo" class object. At least, that's what the error at line 103 is refering to.
I read elsewhere that the error means that I "tried to read more objects than there actually are there". Not sure what that means though, because I just want it to read 1 image - which should be within the object - and return its location.
Also I read that ObjectInputStream never returns null, unless I gave that value somewhere. But it actually is returning(?) "null", even though my code doesn't contain a null value...
I've been at it for days now (yes I am just that bad) and still no luck.
You read it twice:
in.readObject();
photo = (Photo)in.readObject();
Remove the first line.
Also you don't have to create the file. The output stream will do that for you.