So for a project I am working on, I need to be reading binary data from .FRX files into my Java project. Java's standard byte reader however, keeps returning the wrong bytes for me, which I believe could be a result of Java's modified UTF8-encoding. If I use C#'s binary reading methods, I get the output that I require. An obvious (but proving to be difficult) solution is using C# and a DLL to wrap into the Java project, and I was just wondering if anyone has any simpler alternatives in Java, perhaps an alternative standard byte-reader which can be implemented in Java relatively easily.
Any help is greatly appreciated!
Question update
Here is my C# program, which returns the output I am looking for.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
public class GetFromFRX
{
public string getFromFRX(string filename, int pos)
{
StringBuilder buffer = new StringBuilder();
using (BinaryReader b = new BinaryReader(File.Open("frmResidency.frx", FileMode.Open)))
{
try
{
b.BaseStream.Seek(pos, SeekOrigin.Begin);
int length = b.ReadInt32();
for (int i = 0; i < length; i++)
{
buffer.Append(b.ReadChar());
}
}
catch (Exception e)
{
return "Error obtaining resource\n" + e.Message;
}
}
return buffer.ToString();
}
}
And here is some slightly differently formatted Java code:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
public class JavaReader {
public static void main(String[] args) throws Exception {
InputStream i = null;
BufferedInputStream b = null;
try{
// open file
i = new FileInputStream("frmResidency.frx");
// input stream => buffed input stream
b = new BufferedInputStream(i);
int numByte = b.available();
byte[] buf = new byte[numByte];
b.read(buf, 2, 3);
for (byte d : buf) {
System.out.println((char)d+":" + d);
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(i!=null)
i.close();
if(b!=null)
b.close();
}
}
}
In your Java code:
You are using available() in a way which is specifically warned against in the Javadoc.
You aren't checking the result returned by the read() method.
You are reading into the buffer at offset 2 and then checking the entire buffer.
You are reading bytes where your C# code reads characters.
You aren't reading the length word.
You aren't using methods like DataInputStream.readInt() which correspond to your C# code.
Related
I need to read and print some text from the file using NIO. Code works fine with English, but for Russian I need to decode bytes in UTF-8.
I don't understand the order for converting bytes to UTF-8 symbols. Can you help?
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
public class Practice {
public static void main(String[] args) {
try (FileChannel fChan = (FileChannel) Files.newByteChannel(Paths.get("D:/test.txt"))) {
ByteBuffer byteBuf = ByteBuffer.allocate(16);
int count;
do {
count = fChan.read(byteBuf);
if(count != -1) {
byteBuf.rewind();
for(int i = 0; i < count; i++) {
System.out.print((char) byteBuf.get());
}
}
} while(count != -1);
} catch(InvalidPathException e) {
System.out.println("Path exception " + e);
} catch(IOException e) {
System.out.println("IO Exception " + e);
}
}
}
To read UTF-8 encoded text from a ByteBuffer, you can decode it as a CharBuffer:
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(byteBuffer);
For more fine-grained access, use the underlying CharsetDecoder:
CharsetDecoder charsetDecoder = StandardCharsets.UTF_8.newDecoder();
If you truly want to take the raw bytes yourself and decode that using UTF-8, then you first need to learn how UTF-8 works, so do a web search for UTF-8 and start reading, because the way the question is written, it sounds like you don't know that yet. To actually write code for that, you also need to know how to do bit-manipulation in Java, so if you don't know that either, do another web search and start reading. If you can't out that information together to do it, write a new question, explain what you do know, and what is stopping you from applying what you know to the problem.
I tried to make a simple program that copies a file. According to the documentation, FileInputStream.read() and FileOuputStream.write() seemed similar to me. They read and write an int, from and to a file, respectively. So then, why does the following not work?
import java.io.*;
class CopyFile {
public static void main(String[] args) throws IOException {
FileInputStream original = new FileInputStream(args[0]);
FileOutputStream copy = new FileOutputStream(args[1]);
while (original.read() != -1) {
copy.write(original.read());
}
}
}
The resulting file is totally different from the original. Why isn't this working as I expected?
Look at your code:
while (original.read() != -1) {
copy.write(original.read());
}
You read one byte to test if it's end of file, then you read another byte to write.
Hence the byte you read in while condition is skipped.
The correct way is:
int b;
while ((b=original.read()) != -1) {
copy.write(b);
}
I am currently trying to get Java to generate the same hash for a string as PHP's hash algorithm does.
I have come close enough:
hash('sha512', 'password');
outputs:
b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86
Java code:
public static void main(String[] args) {
hash("password");
}
private static String hash(String salted) {
byte[] digest;
try {
MessageDigest mda = MessageDigest.getInstance("SHA-512");
digest = mda.digest(salted.getBytes("UTF-8"));
} catch (Exception e) {
digest = new byte[]{};
}
String str = "";
for (byte aDigest : digest) {
str += String.format("%02x", 0xFF & aDigest);
}
return str;
}
This outputs the same.
My problem is when I use the third argument within PHP's hash function. On PHP's site it's described as following:
raw_output
When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.
I am not quite sure how to implement this extra parameter. I think mainly my question would be, how do I convert a String object into a binary String object? Currently, running it with PHP generates the following: http://sandbox.onlinephpfunctions.com/code/a1bd9b399b3ac0c4db611fe748998f18738d19e3
This should reproduce the outcome from your link:
String strBinary = null;
try {
strBinary = new String(digest, "UTF-8");
} catch (UnsupportedEncodingException e) {
}
and you'll need these imports at the top of your file:
import java.nio.charset.Charset;
import java.io.UnsupportedEncodingException;
I hope I understood your issue correctly.
I run this code, I get "File written !" and when I open the file to see it, every thing that is written is not making any sense. You can understand that I want to write 012345678910 in the file. Is there any other way to write in file than buffW.write(k);. Are there any other mistakes I made?
package thema4_create_write_read_file;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
public class FW {
public static void main(String[] args) {
File newFile = new File("newFile.txt");
if (newFile.exists()) {
System.out.println("The file already exists");
} else {
try {
newFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
try {
FileWriter fileW = new FileWriter(newFile);
BufferedWriter buffW = new BufferedWriter(fileW);
for (int k = 0; k <= 10; k++) {
buffW.write(k); // This is where the problem occurs
}
buffW.close();
System.out.print("File written !");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Is there any way of writing (k) as integer and not as string ,in order to read it as int then?
Bufferedwriter#write(int c):
Writes a single character.
Parameters:
c - int specifying a character to be written
Use Writer#write(String)
writer.write(String.valueOf(integer));
BufferedWriter#write(int i) writes character that corresponds to i in Unicode Table you can take a look what will be written by using
System.out.print((char)k);
Now if you want to write int value of k you should probably use PrintWriter
PrintWriter printW = new PrintWriter(fileW);
printW.print(k);
You can also take a look at PrintStream#print() method (System.out is instance of PrintStream) but Writers are preferred over Streams for character I/O operations.
I'm trying to save a couple of Strings but I'm currently using ObjectInputStream, which apparently doesn't save my data in a permanent manner. Here is the code which I commented in my project. It saves the string in a temporal manner. Anytime I exit my program, puff the data is gone:
ObjectInputStream FileIn= new ObjectInputStream(new FileInputStream("cars.txt"));
//AND HERE IS THE CODE FOR THE RandomAccessFile VERSION:
RandomAccessFile FileIn = new RandomAccessFile("cars.txt", "rw");
au=(Cars)FileIn.readObject(); //THIS readObject(), is giving me errors
//Cars is a Class
Is there any other alternative that I can use to read RandomAccessFile... Please help and thanks.
Just like FileInputStream, you need to wrap a RandomAccessFile in an ObjectInputStream. i.e. RandomAccessFile doesn't buy you anything.
final RandomAccessFile raf = new RandomAccessFile("file.dat", "r");
ObjectInputStream ois = new ObjectInputStream(new InputStream() {
#Override
public int read(byte[] b, int off, int len) throws IOException {
return raf.read(b, off, len);
}
#Override
public int read() throws IOException {
return raf.read();
}
});
For simple String objects is far easier using plain DataInputStream / DataOutputStream:
package test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
public class TestFile {
static final String FILE = "/tmp/cars.txt";
public static void main(String[] args) {
try {
List<String> strs = new ArrayList<String>();
strs.add("Audi");
strs.add("Seat");
strs.add("Renault");
saveStrings(strs);
strs = loadStrings();
System.out.println("Read strings: " + strs);
} catch (Exception e) {
}
}
static List<String> loadStrings() throws Exception {
DataInputStream dis = null;
List<String> list = new ArrayList<String>();
try {
dis = new DataInputStream(new FileInputStream(FILE));
while (dis.available() > 0) {
list.add(dis.readUTF());
}
} finally {
if (dis != null)
dis.close();
}
return list;
}
static void saveStrings(List<String> list) throws Exception {
DataOutputStream dos = null;
try {
dos = new DataOutputStream(new FileOutputStream(FILE));
for (String str : list) {
dos.writeUTF(str);
}
} finally {
if (dos != null)
dos.close();
}
}
}
If you are asking whether you can use RandomAccessFile to seek around inside an object stream and read objects then the short answer is "no". Serialized object streams are heavily encoded with backwards pointers to previously used objects including previously dumped class definitions, etc..
Serialization stream specification with some format details.
Here's some more details on the serialization format.
Discussion about random writing from Java docs.
We had a similar requirement and wrote some code which closes and re-opens the serialized stream once and a while and recorded the positions of these break points. This didn't give us the ability to read a particular object but it did give us the ability to append to serialized stream and to skip over a particular portion of the file -- skip to the next break.
Well you have to invoke, writeObject() instead of readObject() which is actually to read from disk to memory, and of course when the program ends, so does the memory used by that program.