I'm trying to write a program where the user can: 1) Add a person to the contact (name, phone, email), 2) Remove a person from the contacts, 3) Read all from contact.
The Way I'm doing this is I'm asking for the user for their choice and respectively does whatever. For writing, I simply write an object to the file. For removing, I think I'll be asking the user for "last name" which will be used as the KEY (since I'm using a TreeMap)and will remove the value (object) at the key.
So I'm having a problem with reading here. I'm trying to read the object like so:
public void readContact()
{
TreeMap<String, Contact> contactMap = new TreeMap<String, Contact>();
try
{
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(
new FileInputStream(file)));
while( in.available() > 0 ) //This line does NOT read
{
Contact c = (Contact)in.readObject();
contactMap.put(c.getLastName(), c);
}
for(Map.Entry contact : contactMap.entrySet() )
{
Contact con = contactMap.get( contact.getKey() );
System.out.println( con.getLastName() + ", " + con.getFirstName() + ": " + con.getPhoneNumber() + "\t" + con.getEmail());
}
}
catch(Exception e)
{
System.out.println("Exception caught");
}
}
Please do not suggest doing something like while(true) until I get the EOFException because:
that isn't what exception handling is for I believe
I still have more things to do after this so I can't have the program terminating'
Please do not suggest doing something like while(true) until I get the EOFException
That is exactly what I suggest. When you are searching for answers it is counter-productive to circumscribe the solution space according to arbitrary criteria like this.
because:
that isn't what exception handling is for I believe
When an API that you are calling throws an exception, as this one does, you don't have any choice but to catch it. Whatever you may think about 'what exception handling is for', you are subject to what the designers of the API thought when they designed the API.
I still have more things to do after this so I can't have the program terminating'
So don't terminate it. Catch EOFException, close the input, and break out of the loop.
I have seen more costly programming time wasted over 'what exception handling is for' than I can really credit.
I know that you are looking for an answer that is not using exception handling, but I believe in this case using EOFException to determine when all input has been read is the right way.
The JavaDoc of EOFException states that
This exception is mainly used by data input streams to signal end of stream. Note that many other input operations return a special value on end of stream rather than throwing an exception.
So, there are input streams that use other means to signal an end of file, but ObjectInputStream#readObject uses ObjectInputStream$BlockDataInputStream#peekByte to determine if there is more data to read, and peekByte throws an EOFException when the end of the stream has been reached.
So it is feasible to use this exception as an indicator that the end of the file has been reached.
To handle the exceptions without interrupting the program flow, some of the possible exceptions should be passed up in the hierarchy. They can be handled by a try - catch block in the code that calls readContact().
The EOFException can simply be used as an indicator that we are done reading the objects.
public TreeMap<String, Contact> readContact() throws FileNotFoundException,
IOException, ClassNotFoundException {
TreeMap<String, Contact> contactMap = new TreeMap<String, Contact>();
// The following call can throw a FileNotFoundException or an IOException.
// Since this is probably better dealt with in the calling function,
// readContact is made to throw these exceptions instead.
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(
new FileInputStream(file)));
while (true) {
try {
// Read the next object from the stream. If there is none, the
// EOFException will be thrown.
// This call might also throw a ClassNotFoundException, which can be passed
// up or handled here.
Contact c = (Contact) in.readObject();
contactMap.put(c.getLastName(), c);
for (Map.Entry<String, Contact> contact : contactMap.entrySet()) {
Contact con = contact.getValue();
System.out.println(con.getLastName() + ", "
+ con.getFirstName() + ": " + con.getPhoneNumber()
+ "\t" + con.getEmail());
}
} catch (EOFException e) {
// If there are no more objects to read, return what we have.
return contactMap;
} finally {
// Close the stream.
in.close();
}
}
}
- Exceptions are not only used in order to raise an alarm when something goes wrong while calling a method, but are also used in Threads and IO with various other uses.
- You can use Exception to indicate end of the file.
- Use the try-catch combo to work along with the above to keep the flow of the program smooth.
Why so much trouble while reading object from file, just save a hash map into a file and read the same once from file then perform any operation.
Also I would suggest to use any one of object oriented database like Db4o to do this quickly then you never worry about end of file exception
'ObjectInputStream.available returns 0' is a known problem, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4954570, and since we cannot use it I think EOFException would be a reasonable approach in your situation. Catching EOFExcepion will not terminate your program.
You could write the number of objects to your file with ObjectOutputStream.writeInt, and then you would read this number with ObjectInputStream.readInt and know how many objects to read
You could use null as EOF marker.
You could save your objects as an array or List or even Map and then read them with one readObject.
What you have discovered
You found out about FileInputStream.available() returning 0 even though there are unread bytes in the file! Why is this? This could happen (rendering FileInputStream.available() unreliable for a couple of reasons:
According to this documentation, FileInputStream.available() approximates the number of bytes that can be read without blocking
The hard disk drive itself might change its operation mid-read (go from spinning to not spinning)
The file you are trying to access is either a file on a remote system or a device file : May the FileInputStream.available foolish me?
The FileInputStream might be blocked
Some alternative way
As an alternative to relying on EOFException to close the file, you could use a (very-small!) binary file that keeps track of the number of Objects in your file. (Judging from your code, it looks like you are simply writing Objects to the file.) The way I have used this is just to
store the number of bytes the number itself will consume
using that number of bytes, store the number itself
For example, the first time the serialization file is created, I could make the binary file store 1 1 (which specifies that the number of Objects in the serialization file takes up 1 byte, and that number is 1). This way, after 255 Objects (remember, an unsigned byte can only store up to 28-1 == 255), if I write another Object (Object number 256 up to 2562-1 == 65535), the binary file will have, as contents, 2 1 0, which specifies that the number takes up 2 bytes and is 1*2561+0 == 256. Provided that the serialization is reliable (good luck on ensuring that: http://www.ibm.com/developerworks/library/j-serialtest/index.html), this method will let you store (and detect) up to 256255-1 bytes (which pretty much means that this method works indefinitely).
The code itself
How something like that would be implemented would be something like:
ObjectOutputStream yourOutputStream = new ObjectOutputStream(new FileOutputStream(workingDirectory + File.separatorChar + yourFileName); //The outputStream
File binaryFile = new File(workingDirectory + File.separatorChar + nameOfFile); //the binary file
int numOfObjects = 0, numOfBytes; //The number of Objects in the file
//reading the number of Objects from the file (if the file exists)
try
{
FileInputStream byteReader = new FileInputStream(binaryFile);
numOfBytes = byteReader.read();
//Read the rest of the bytes (the number itself)
for (int exponent = numOfBytes; exponent >= 0; exponent--)
{
numOfObjects += byteReader.read() * Math.pow(256,exponent);
}
}
catch (IOException exception)
{
//if an exception was thrown due to the file not existing
if (exception.getClass() == FileNotFoundException.class)
{
//we simply create the file (as mentioned earlier in this answer)
try
{
FileOutputStream fileCreator = new FileOutputStream(binaryFile);
//we write the integers '1','1' to the file
for (int x = 0; x < 2; x++) fileCreator.write(1);
//attempt to close the file
fileCreator.close();
}
catch (IOException innerException)
{
//here, we need to handle this; something went wrong
innerException.printStackTrace();
System.exit(-1);
}
}
else
{
exception.printStackTrace();
System.exit(-2);
}
}
Now, we have the number of Objects in the file (I leave it to you to figure out how to update the bytes to indicate that one more Object has been written when yourOutputStream calls writeObject(yourObject);; I have to go clock in.)
Edit: yourOutputStream is either going to write over all the data in the binaryFile or append data to it. I just found out that RandomAccessFile would be a way to insert data into anywhere in the file. Again, I leave details to you. However you want to do it.
You can write the last object as null.
And then iterate till you get a null at the reading side.
e.g.
while ((object = inputStream.readObject()) != null) {
// ...
}
Related
The problem I seem to have hit is one relating to loading times; I'm not running on a particularly fast machine by any means, but I still want to dabble into neural networks. In short, I have to load 336,600,000 integers into one large array (I'm using the MNIST database; each image is 28x28, which amounts to 748 pixels per image, times 45,000 images). It works fine, and surprisingly I don't run out of RAM, but... it takes 4 and a half hours, just to get the data into an array.
I can supply the rest of the code if you want me to, but here's the function that runs through the file.
public static short[][] readfile(String fileName) throws FileNotFoundException, IOException {
short[][] array = new short[10000][784];
BufferedReader br = new BufferedReader(new FileReader(System.getProperty("user.dir") + "/MNIST/" + fileName + ".csv"));
br.readLine();
try {
for (short i = 1; i < 45000; i++) {
String line = br.readLine();
for (short j = 0; j < 784; j++) {
array[i][j] = Short.parseShort(line.split(",")[j]);
}
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
return array;
}
What I want to know is, is there some way to "quicksave" the execution of the program so that I don't have to rebuild the array for every small tweak?
Note: I haven't touched Java in a while, and my code is mostly chunked together from a lot of different sources. I wouldn't be surprised if there were some serious errors (or just Java "no-nos"), it would actually help me a lot if you could fix them if you answer.
Edit: Bad question, I'm just blind... sorry for wasting time
Edit 2: I've decided after a while that instead of loading all of the images, and then training with them one by one, I could simply train one by one and load the next. Thank you all for your ideas!
array[i][j] = Short.parseShort(line.split(",")[j]);
You are calling String#split() for every single integer.
Call it once outside the loop and copy the value into your 2d array.
So I asked this question a few days ago, but maybe I can elaborate a bit more, or in a different way now. I am a big java and android newbie, so it takes a lot of time to figure stuff out for me. I have a Bluetooth connecting between 2 devices. I tried using sensors and everything works fine. The devices connect and they send sensor values to one another.
This sensor value, however, is auto-generated. What I want is to get DB values from one of the devices, convert them to bytes, add them to a byte array and send this byte array as a single message to the other device, where it is going to reverse the process. I have everything set up, everything is as it should be with only 1 exception - I need to somehow catch the incomingMessage as a byte array, so I can finish the process.
How can I get the value of the incomingMessage(which is supposed to be transferring a byte array) and add it to another byte array that I am then "decoding"?
The commented out one is the example that I tried and was working.
if (mBluetoothConnection.incomingMessage != null) {
//messageTemp = mBluetoothConnection.incomingMessage;
msg = mBluetoothConnection.incomingMessage;
}
The one that is not commented out is the one, whose value I want to assign to a byte array:
byte[] array = msg;
This is the only thing that I have not been able to figure out so far.
My current issue is that "array" returns null object reference.
Please, help me! I feel like I have almost connected 2 bridges and the paint on each differest by just a centimeter from being okay.
Alright, I managed to figure it out, but forgot to update, here is my other post with a little bit more code:
How can I assing the value of an incoming Bluetooth message to a byte array which I want to decode into integers?
Here's what I changed:
I only touched the run() method in my BluetoothConnectionService
Instead of using the byte[] buffer, as I mention in the commented code, I declared a public static byte[] incomingBytes and gave it a size of 44, since this is what my 11 integer array going to need. Then I just replaced the "buffer" with "incomingBytes" in the example code, and looks like this:
public static byte[] incomingBytes = new byte[44];
public void run(){
//byte [] buffer replaced with incomingBytes
byte[] buffer = new byte[44]; // this was in the example, but it is not used. It was replaced by incomingBytes, declared at the start of the class
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
// Read from the InputStream
try {
bytes = mmInStream.read(incomingBytes);
incomingMessage = new String(incomingBytes, 0, bytes);
Log.d(TAG, "InputStream: " + incomingMessage);
} catch (IOException e) {
Log.e(TAG, "write: Error reading Input Stream. " + e.getMessage() );
break;
}
}
}
Then I only need to call incomingBytes for my convertion in the other class and it works fine.
What I am trying to do is assign a number value to a group of zip codes and then use that number to do a calculation later on in the program. What I have now is
if (zip == 93726 || zip == 93725 || zip == 92144) {
return 100;
}
else if (zip == 94550 || zip == 34599 || zip == 77375) {
return 150;
}
and then I take the variable and use it in a calculation. Assigning the number to the variable and the calculation all work but what I have ran into is apparently android only allows you to have so many lines of code and I have ran out of lines with just using if else statements. My question is what would be a better what to go about this?
I am not trying to assign a city to each zip because I have seen that they have services that do that from other posters.
a. You can either use a
switch (zip)
{
case 93726: case 93725: case 92144: return 100;
case 94550: case 34599: case 77375: return 150;
}
-
b. or create a HashMap<Integer,Integer> and fill it with 'zip to value' entries, which should give you a much better performance if you have that many cases.
Map<Integer,Integer> m = new HashMap<>();
m.put(93726,100);
later you could call
return m.get(zip);
-
c. If your zip count is in the tens of thousands and you want to work all in memory, then you should consider just holding a hundred-thousand int sized array:
int[] arr=new int[100000];
and filling it with the data:
arr[93726]=100;
.
.
.
You should probably use String constants for you ZIP codes since
in some places, some start with 0
in some places, they may contain letters as well as numbers
If you are using an Object (either String or Integer) for your constants, I have often used Collection.contains(zip) as a lazy shortcut for the condition in each if statement. That collection contains all the constants for that condition, and you would probably use a subclass that is geared towards finding, perhaps HashSet. Keep in mind that if you use a HashMap solution as suggested elsewhere, your keys will be Integer objects too, so you will do hashing on the keys in any case, you just won't need to store the result values in the collection suggestion.
I suspect that for a large collection of constants, hashing may turn out to be faster than having to work through the large number of == conditions in the if statement until you get to the right condition. (It may help a bit if the most-used constants come first, and in the first if statement...)
On a completely different note (i.e. strategy instead of code), you should see if you could group your ZIPs. What I mean is for example, that if you know that all (or most) ZIPs of the forms "923xx" and "924xx" result in a return of 250, you could potentially shorten your conditionals considerably. E.g. zip.startsWith("923") || zip.startsWith("923") for String ZIPs, or (zip / 100) == 923 || (zip / 100) == 924 for int.
A small number of more specific exceptions to the groups can still be handled, you just need to have the more specific conditionals before the more general conditionals.
Use declarative data. Especially as the zip codes might get updated, extended, corrected:
Using for instance a zip.properties
points = 100, 150
zip100 = 93726, 93725, 92144
zip150 = 94550, 34599, 77375,\
88123, 12324, 23424
And
Map<Integer, Integer> zipToPoints = new HashMap<>();
If you got ZIP codes with leading zeroes maybe better use String or take care to parse them with base 10 (leading zero is base 8, octal).
Whether there really exists such a limitation I do not know, but the extra effort of a bit of coding is worth having all as data.
Have a map of the zip codes.just return the value.
Map<Integer,Integer> zipValues = new HashMap<Integer,Integer>();
zipValues.put(93726,100);
.
.
And so on. or u can read from a prop file and populate the map.
then instead of using the if(s),
return zipValues.get(zipCode);
so say zipCode=93726, it will return u 100.
Cheers.
You could create a Map which maps each zip code to an integer. For example:
Map<Integer, Integer> zipCodeMap = new HashMap<>();
zipCodeMap.put(93726, 100);
And later you can retrieve values from there.
Integer value = zipCodeMap.get(93726);
Now you still have to map each zipcode to a value. I would not do that in Java code but rather use a database or read from a text file (csv for example). This depends mostly on your requirements.
Example csv file:
93726, 100
93727, 100
93726, 150
Reading from a csv file:
InputStream is = this.class.getResourceAsStream("/data.csv");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
try {
String line;
while ((line = reader.readLine()) != null) {
String[] row = line.split(",");
int zip = Integer.parseInt(row[0].trim());
int value = Integer.parseInt(row[1].trim());
zipCodeMap.put(zip, value);
}
}
catch (IOException ex) {
// handle exceptions here
}
finally {
try {
is.close();
}
catch (IOException e) {
// handle exceptions here
}
}
I'm trying to read the ex2data2.txt which contains dataset with 3 columns. I want to store it in my x array and y array. but it is not working. it cannot read the text file. the location of text file is in my src folder along with my codes.
double[][] x = new double[180][1];
double[][] y = new double[180][0];
try{
BufferedReader br=new BufferedReader(new FileReader("ex2data2.txt"));
String words[]=new String[2];
String line=null;
int i = 0;
while((line=br.readLine())!=null){
words=line.split(",");
//double[i] y = Double.parseDouble(words);
x[i][0] = Double.parseDouble(words[0]);
x[i][1] = Double.parseDouble(words[1]);
y[i][0] = Double.parseDouble(words[2]);
i++;
}
br.close();
}
catch(Exception e){
System.err.println("Error: Target File Cannot Be Read");
}
You should put the file in the top, parent project folder. not in src/.
Edit : I have run this, for proof...
Accessing file, read all the data.
java.lang.NumberFormatException: For input string: "43 323 33" this I have put in that file
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1241)
at java.lang.Double.parseDouble(Double.java:540)
at com.rem.so.Rem.main(Rem.java:18)
Next run
java.lang.ArrayIndexOutOfBoundsException: 1
at com.rem.so.Rem.main(Rem.java:19)
After correcting this..
double[][] x = new double[180][2];
double[][] y = new double[180][1];
it is now done.
Please find the screenshot where I have put the file...
double[][] y = new double[180][0];
That's probably not what you wanted. The second dimension is zero so you wont be able to put anything in that array. The second dimension needs to be at least 1.
catch(Exception e){
System.err.println("Error: Target File Cannot Be Read");
}
Any developer writing this code should be immediately fired.
Never catch an Exception, but perform proper and specific error handling. Catch the most precise error to handle (e.g. FileNotFoundException), avoid catching errors that you do not know how to handle. If in doubt, rethrow the error, so that an outer error handler can process it. Always log the error, unless it is expected to happen.
Then you would be getting a more precise error message. But you opted to ignore the actual error e.
REALLY REALLY read a Java book or tutorial, in particular the section on proper exception handling. You are making your own live difficult by discarding the error the way you have been doing it.
An exception is almost never something you should ignore. You are required to handle them for a reason! (In fact, there are also "unchecked" exception, where you are not required to do so. Which makes it even more obvious that here, you need to handle them properly.)
Three Rules for Effective Exception Handling (java.net)
Your error most likely is an ArrayOutOfBoundsException (which you should not have caught!)
double[][] x = new double[180][1];
double[][] y = new double[180][0];
this is too small. you probably need
double[][] x = new double[180][2];
double[][] y = new double[180][1];
I am trying to use a bubble sort ( i know its very inefficient ) to sort some data, but my code is behaving quite strangely, after exactly 926 passes of the outer while loop, an IOException is thrown, this is independent of the data inputed, I've checked and it dont seem to be related to the amount of memory available, the code and exception are below:
public static void sort(String f1, String f2) throws FileNotFoundException, IOException {
RandomAccessFile reader = new RandomAccessFile(f1,"rw");
RandomAccessFile writer = new RandomAccessFile(f1,"rw");
// start the bubble sort
int limit = (int) reader.length()/4;
while (limit>1) {
DataOutputStream writerstream = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(writer.getFD())));
DataInputStream readerstream = new DataInputStream(
new BufferedInputStream(new FileInputStream(reader.getFD())));
// the first value, a is the first value in the file
int a = readerstream.readInt();
int myfilepointer = 4;
// this flag is used to stop passing through when correct order is detected
boolean setpass = false;
// pass through the file
while (myfilepointer<limit*4) {
// the second value, b is the next value in the file
//System.out.println(myfilepointer);
int b = readerstream.readInt();
myfilepointer += 4;
// test if a and b are in the correct way around
// if wrong way around then b is written and the next a value is the same as before
if (a>b) { writerstream.writeInt(b); setpass = false; }
// if the correct way about then a is written and the next a value is the same as the previous b value
else { writerstream.writeInt(a); a = b; }
}
// this last value is the a value of exiting the while loop
writerstream.writeInt(a);
// write the new data to the file
writerstream.flush();
writer.seek(0);
reader.seek(0);
// if there was no swaps then the order is correct so exit loop
if (setpass == true) break;
limit -= 1;
}
}
and the exception thrown is below
Exception in thread "main" java.io.IOException: Read error
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(Unknown Source)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
at java.io.DataInputStream.readInt(Unknown Source)
at uk.ac.cam.hh360.fjava.tick0.ExternalSort.sort(ExternalSort.java:48)
at uk.ac.cam.hh360.fjava.tick0.ExternalSort.main(ExternalSort.java:119)
One potential problem is that you are not closing the streams opened in outer loop.
You're writing to the same file you're reading. So as soon a you write your first integer to the writer stream, the contents of the file is replaced by what you've written. Since you're using a BufferedOutputStream, it might in fact happen later than the first time you're writing.
You should read all the integers in memory, close the input stream, sort the integers in memory, and then write all the integers to the file.
I don't understand why you're using a random access file just to get a file descriptor and the open streams on the file. Either you want to access it randomly, or you want to access it using streams. But you can't do both.