But when I tested it, it failed at dbFile.write(b) and the IOException says: Access Denied. I'm really stuck there without anyway to sovle it. So anybody who can point out what�s wrong here? Or what�s your way to write record to db file? Thanks a lot!
[Enclosed the code excerpt in CODE tags]
[ June 08, 2004: Message edited by: Philippe Maquet ]
Welcome to JavaRanch and this forum!
Javini's suggestion probably will solve the issue.
Just a comment about the code posted above: why do you write each field value separately? You could prepare a buffer (array of bytes) for the whole record, and then write it in one operation.
Will the grader care?
I really don't know for the *actual* grader. But I know that if I was, I would...
Now seriously, I think that read *once* or even a few times in the project, such a lack of optimization (BTW, that code is even not simpler than a much better one, it's "just" slower) shouldn't lead to a lower score. But in case it'd be repeated regularly in the whole project, I fear that the grader would think: "OK, it works, but he's not a good coder". And would *you* give a high score to an average coder for a *developer* exam?
Today, I had to grade 17 small EJB development assignments. I didn't care for pure coding practices because it was not in my objectives for that exam (pure EJB knowledge). But I can tell you that:
But now I have another question. Simply put, if String  rec represents the whole record, and each element rec, rec�� corresponds to each field, which has a fixed length, namely 32, 64, 6, 4, 6, 8, 8. So most likely these elements will have some space at the end. Now, what I want to do is: update one element without changing its original length, say, I want to change the rec to a string �Have a try� followed by a string of space which will make its total length keep to 64. I have tried several ways but never worked. No matte which way I used, the rec�s length will be cut off to the length of the string assigned to it. In other words, the space at the end will be cut off. Is it possible to implement what I wanted to do? Or maybe my idea is not right, anybody can give me some helps?
Does the following help?
1� allocate a bytes array for the record: new byte[recordLength]; // recordLength == 128 in your example
// notice that your bytes array is automatically filled with 0s
2� for each field:
2.a - get its bytes representation by a call to String.getBytes(String charsetName)
2.b - check that the field length is not overflowed or throw some IllegalArgumentException
2.c - use System.arraycopy() to copy the field's bytes array in the record's bytes
array at the right place (field's offset)
3� write the record's bytes array in the file.
I'm still having trouble in this read-write problem. I tried your way and everything works well except the one byte delete flag. I'm stuck there getting nowhere. I described the problem briefly as following:
In the readData() which I wrote myself (BTW, the purpose I wrote this method is to read data from db file and save them to a HashMap which uses the recNo as key as String as value), the code related to the delete flag is:
Comment: this recordData will be saved as a value into a HashMap.
In the writeRead() which I wrote myselft, the code related to the delete flag is:
The problem is: Before I did any writeRead operation, the two system.out will get right answer:
The length of flag is:1
The content of flag is: 0.
But once I called writeRead to update any record, the system.out of that record will be:
The length of flag is:2
The content of flag is: 48 (or something other numbers).
What's the problem here? I've been working on it whole day. I would really appreciate your help or advice.
[Andrew: put the source code between [code] and [/code] UBB tags]
[ June 10, 2004: Message edited by: Andrew Monkhouse ]
I have edited your post to put the code between [code] and [/code] UBB tags. Doing this ensures that indenting is preserved, which makes the code easier to read.
When you are writing your post, there are a number of buttons just below the edit pane, which will insert the tags for you, so you don't have to remember what they are.
If you would like to edit your original post so that you can see what I have done, you can click on the button that is just above your post.
There are a few problems with the code you posted. But I suspect the problem that you are experiencing is with the code you haven't posted - the bit marked "???" in the writeRead() method. I suspect you are not changing your pointer to the position in the "recordBuffer" as you try and fill it.
So if (as I suspect) you did something like:
then the subContractor data will overwrite the deleted flag data, and then the city data will overwrite the subContractor data, and the ....
What you need to be doing is updating the position in the record buffer where you are copying the new data:
(Note: as Phil mentions earlier, you should also be checking for sizes of the data you are copying, and throwing an exception if the size is incorrect.)
Another problem is that your "recordData" object is an array of Strings. This means that you must coerce the deleted flag (which is a byte) into a String. If you made recordData an array of Objects then you could store the Byte directly into the recordData without converting to and from a String.
You have made a mistake with converting back from the String representation of the byte back into the byte. If it hadn't been for the other problems, this particular problem may have gone unnoticed, as it only causes problems when you are converting a byte which has more than one digit. If you have a byte which contains the number 45, then convert that into a String, it is stored as the String "45". If you call the getBytes() method on any String, it returns the bytes needed to represent the String. In the case of the String "45", it will return two bytes - the byte representing the "4", and the byte representing the "5" (and this is just ASCII - you could end up with far more complex conversions). What you need to do is create a Byte() from the String, then get the byteValue of it. (But, as I mentioned earlier, if you use an Object you will not need this conversion to/from Strings anyway ).
The fact that you store the deleted flag value as a String in the field values array of Strings looks weird to me. Check your specific instructions, but it's highly probable that the deleted flag is not to be included in the array returned by readRecord().
Now to fill your recordBuffer (which BTW and on the contrary of what I wrote in a previous post should be allocated with a length of recordLength + 1 (or + 2 if your deleted flag is a short)):
[ June 12, 2004: Message edited by: Philippe Maquet ]
Just to clarify your issue with using an Object instead of a String - all it means is that you would change the following code:
When you try to get the data out again, you will need to cast the object stored back into it's real data type:
But you also need to note Phil's comment above about what you are sending back to the client. You mentioned that you are storing the records in a HashMap, in which case you can store the deleted flag with the record, and you can use an Object for this.
In the readData method, to read each record data, I used the following code:
In the writeData method, to write the updated record back to db file, the
related code is here:
My question here is: in the readData(), I System.out.println the total length of currentRecordData, the length of currentRecordData, and content of currentRecordData. Before I used the writing operation, the total length of currentRecordData is 183, which is the length of all the data fields(32,64,64,6,8, 8) plus the one byte delete flag length. And the length of currentRecordData and content of currentRecordData are 1 and 0 respectively. However, after I used the writing operation, these three will be changed to: 184, 2, 48(or some other numbers), respectively. The db file will look like (please see the row 5, which I updated):
You will see the delete flag is different between the two, also the second field which I updated intentionally has some unreadable signs instead of space, this is another problem I want to ask.
I hope this email will make it clear to you. And I really appreciate your time and help.
[Phil: corrected use of CODE tags]
[ June 13, 2004: Message edited by: Philippe Maquet ]
Originally posted by Dave Gear:
I'm getting more and more confused about this one byte delete flag? It should be saved in the String with those other record fields? For example, there is a method: public String readRecord(long recNo). The return value of this method is a String, which represents the whole record. What I'm thinking is I save the one byte delete flag as the first element of this String. I can't find out other ways to bundle this flag to the paticular record?
Ahh: but if the record is deleted, you cannot read it
Does your readRecord method throw an exception? or have have some other way of indicating that the record does not exist?
If so, then you do not need to worry about storing or returning the delete flag. If the flag indicates that the record has been deleted, you throw the appropriate exception, or do whatever else is appropriate. If the flag indicates that the record has not been deleted then you return all the fields of the record (which do not include the deleted flag).
(See my post just above this one first - you probably do not need the information in this post now).
Originally posted by Dave Gear:
In the writeData method, to write the updated record back to db file, the
related code is here:
As I mentioned earlier, this code is wrong.
Originally posted by Andrew Monkhouse:
You have made a mistake with converting back from the String representation of the byte back into the byte. If it hadn't been for the other problems, this particular problem may have gone unnoticed, as it only causes problems when you are converting a byte which has more than one digit. If you have a byte which contains the number 45, then convert that into a String, it is stored as the String "45". If you call the getBytes() method on any String, it returns the bytes needed to represent the String. In the case of the String "45", it will return two bytes - the byte representing the "4", and the byte representing the "5" (and this is just ASCII - you could end up with far more complex conversions). What you need to do is create a Byte() from the String, then get the byteValue of it.
There are other problems which need to be fixed, but start with the basics:
Do not attempt to getBytes from the String - this is wrong: it will return the bytes that can be used to recreate the String. That is:
I use stringVar.getBytes("US-ASCII") to get an array of bytes for the string. I think this is ok for my assignment as it states
All numeric values are stored in the header information use the formats of the DataInputStream and DataOutputStream classes. All text values, and all fields (which are text only), contain only 8 bit characters, null terminated if less than the maximum length for the field. The character encoding is 8 bit US ASCII.
Your usage is fine, but it is different from what Dave is trying to achieve.
You are trying to get the byte corresponding of an 8 bit US ASCII string to put in a file. In other words, the exact bytes that make up the String.
Dave is trying to get the byte that is represented in the string.
But now I have One more question:
Just for the reason of test, I read data from the db file to another text file(I call it daveTest) in which the layout of the data makes it easier to read, row by row, field by field. For most of the fields, there are some spaces at the end because it�s not possible they have exactly the same length they should have.
My question is as following: when I used my writeData which we discussed before to update a field to db file and read it again to daveTest file. When I opened the daveTest file using a kind of text editor, which is called editplus, for that updated field, the spaces at the end have been taken place by a string of unreadable small scares. But, if I used Microsoft�s Notepad or Wordpad to open this file, they are still spaces.
Maybe this is not a big deal, but I�m just afraid I did something wrong. Anyone can give some comments on this?
That is good news.
The squares shown at the end of the string are the editor's way of showing you that there is something there that it cannot display using the normal US ASCII character set. Different editors handle this in different ways - some show the squares (as you saw), some show spaces (as you also saw), and some use some special indicator to display the character (e.g. depending on the editor, '\n' might be shown as '\n' or '^n' or something else).
In your case, I suspect that the invisible characters are the NULL character: "0x00" - giving you null terminated strings. Which your instructions probably tell you are used in the database file, but obviously aren't used, or you wouldn't have noticed them :roll: .
Now you will have to make a design decision (and document it ) - do you go back and fill the String with spaces to match the existing file, or do you write your code to handle either spaces or nulls (which are allowed in the instructions). Your choice.
It may seem that at present handling nulls may be easier, but if you don't understand why they are there / how to get rid of them, then you may want to look into changing them to spaces, just for your own eductational purposes.
Well, Andrew, I can't express how many thanks I own to you. Same thanks to Phillippe and anyone who concerned this thread.