I have below code which is used to write the list array into a dat file , I ran on OnePlus2 and the IDE is Android Studio 1.3.
private void writeToFile(List<Short> list) throws IOException {
String stringTransform = transform(list);
String str = new String(stringTransform.getBytes(), "ascii");
byte[] bytes = new byte[str.length() / 8];
char chatAt;
for (int i = 0; i < str.length() / 8; i++) {
for (int j = 0; j < 8; j++) {
chatAt = str.charAt(i * 8 + j);
if (chatAt == '1') {
byte b = (byte) (0x80 >> j);
bytes[i] = (byte) (bytes[i] | b);
}
}
}
FileOutputStream fos = new FileOutputStream("/sdcard/1.dat");
fos.write(bytes);
fos.close();
fos.flush();
}
private String transform(List<Short> list) {
StringBuilder sb = new StringBuilder(list.size());
for (Short integer : list) {
sb.append(integer);
}
return sb.toString();
}
However , I input the same data in different time , and the dat file which is generated will show different content , as the pictures show:
This is not about your code. This is about program and encoding you using. Try to change encoding in your editor. If it is binary file I would recommend sublimetext 3 with HexViewer plugin:
Related
I want to develop a OTPInputStream in Java that extends the InputStream and takes another input stream of key data and provides a stream encrypting / decrypting input stream.I need to develop a test program to show the use of OTPInputStream that uses XOR and arbitrary data.
I tried with this code but I have problem that is
java.io.FileInputStream cannot be cast to java.lang.CharSequence
What should I do here?
public class Bitwise_Encryption {
static String file = "" ;
static String key = "VFGHTrbg";
private static int[] encrypt(FileInputStream file, String key) {
int[] output = new int[((CharSequence) file).length()];
for(int i = 0; i < ((CharSequence) file).length(); i++) {
int o = (Integer.valueOf(((CharSequence) file).charAt(i)) ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i] = o;
}
return output;
}
private static String decrypt(int[] input, String key) {
String output = "";
for(int i = 0; i < input.length; i++) {
output += (char) ((input[i] - 48) ^ (int) key.charAt(i % (key.length() - 1)));
}
return output;
}
public static void main(String args[]) throws FileNotFoundException {
FileInputStream file = new FileInputStream("directory");
encrypt(file,key);
//decrypt();
int[] encrypted = encrypt(file,key);
System.out.println("Encrypted Data is :");
for(int i = 0; i < encrypted.length; i++)
System.out.printf("%d,", encrypted[i]);
System.out.println("");
System.out.println("---------------------------------------------------");
System.out.println("Decrypted Data is :");
System.out.println(decrypt(encrypted,key));
}
}
Think what you want is just file.read() and file.getChannel().size() to read one character at a time and get the size of the file
Try something like this:
private static int[] encrypt(FileInputStream file, String key) {
int fileSize = file.getChannel().size();
int[] output = new int[fileSize];
for(int i = 0; i < output.length; i++) {
char char1 = (char) file.read();
int o = (char1 ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i] = o;
}
return output;
}
Will have to do some error handling because file.read() will return -1 if the end of the file has been reached and as pointed out reading one byte at a time is lot of IO operations and can slow down performance. You can keep the data in a buffer and read it another way like this:
private static int[] encrypt(FileInputStream file, String key) {
int fileSize = file.getChannel().size();
int[] output = new int[fileSize];
int read = 0;
int offset = 0;
byte[] buffer = new byte[1024];
while((read = file.read(buffer)) > 0) {
for(int i = 0; i < read; i++) {
char char1 = (char) buffer[i];
int o = (char1 ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i + offset] = o;
}
offset += read;
}
return output;
}
This will read in 1024 bytes at a time from the file and store it in your buffer, then you can loop through the buffer to do your logic. The offset value is to store where in our output the current spot is. Also you will have to make sure that i + offset doesn't exceed your array size.
UPDATE
After working with it; i decided to switch to Base64 Encoding/Decoding to remove non-printable characters:
private static String encrypt(InputStream file, String key) throws Exception {
int read = 0;
byte[] buffer = new byte[1024];
try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
while((read = file.read(buffer)) > 0) {
baos.write(buffer, 0, read);
}
return base64Encode(xorWithKey(baos.toByteArray(), key.getBytes()));
}
}
private static String decrypt(String input, String key) {
byte[] decoded = base64Decode(input);
return new String(xorWithKey(decoded, key.getBytes()));
}
private static byte[] xorWithKey(byte[] a, byte[] key) {
byte[] out = new byte[a.length];
for (int i = 0; i < a.length; i++) {
out[i] = (byte) (a[i] ^ key[i%key.length]);
}
return out;
}
private static byte[] base64Decode(String s) {
return Base64.getDecoder().decode(s.trim());
}
private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
This method is cleaner and doesn't require knowing the size of your InputStream or do any character conversions. It reads your InputStream into an OutputStream to do the Base64 Encoding as well to remove non printable characters.
I have tested this and it works both for encrypting and decrypting.
I got the idea from this answer:
XOR operation with two strings in java
I keep getting the following error when I run my program:
java.lang.OutOfMemoryError : Java heap space
I tried fixing this by adding -Xms512M -Xmx1524M to both Program arguments and VM arguments (I use eclipse), but this doesn't seem to prevent the error.
If the solution is adding more memory in eclipse run configuration, the question is > is this going to be exported too? or is it just for me, how can I make sure this doesn't happen on other computers?
Current code
private static void checkSumGen() throws IOException NoSuchAlgorithmException
{
File plFolder = new File(".\\Plugins");
File[] listOfFiles = plFolder.listFiles();
List<String> listClone = new ArrayList<String>();
for (int i = 0; i < listOfFiles.length; i++)
{
File file = listOfFiles[i];
String fileloc = file.getAbsolutePath();
MessageDigest md = MessageDigest.getInstance("SHA-256");
FileInputStream fis = new FileInputStream(fileloc);
byte[] dataBytes = new byte[1024];
int nread = 0;
while ((nread = fis.read(dataBytes)) != -1)
{
md.update(dataBytes, 0, nread);
} ;
byte[] mdbytes = md.digest();
// convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i1 = 0; i1 < mdbytes.length; i++)
{
sb.append(Integer.toString((mdbytes[i1] & 0xff) + 0x100, 16).substring(1));
}
System.out.println("Hex format : " + sb.toString());
// convert the byte to hex format method 2
StringBuffer hexString = new StringBuffer();
for (int i2 = 0; i2 < mdbytes.length; i++)
{
hexString.append(Integer.toHexString(0xFF & mdbytes[i2]));
}
System.out.println("Hex format : " + hexString.toString());
}
}
You have an infinite loop in your code that causes the OutOfMemoryError.
In:
for (int i1 = 0; i1 < mdbytes.length; i++)
you increment i instead of i1 causing i1 < mdbytes.length to be true forever.
I have 6 columns in one table and one of the column contains Chinese character and I have 200 records in that table.
I have written the code to save it one text file. The problem is while fetching all records, I am able to see the chinese text in the file. But while fetching only one record I am seeing the Chinese text is garbled.
I am using the below code.
public static void main(String args[]){
String outputFile = fileNameEncode("C:\\a\a.txt");
FileOutputStream os = new FileOutputStream(outputFile);
writeToFile(os);
}
private static String fileNameEncode(String name) {
String file;
try {
byte[] utf_byte = name.getBytes("UTF-8");
StringBuilder sb = new StringBuilder(1024);
for (byte b : utf_byte) {
int integer = b & 0xFF; // drop the minus sign
sb.append((char) integer);
}
file = sb.toString();
} catch (Exception e) {
file = name;
}
return file;
}
public void writeToFile(FileOutputStream os) {
PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(ostream, "GBK")));
for (int rowNum = 0; rowNum < arrayList.size(); rowNum++) {//arrayList contains data from db
ArrayList list = arrayList.get(rowNum);
for(int k = 0; k < list.size(); k++{
String[] data = new String[6];
for (int colNum = 0; colNum < 6; colNum++) {
data[colNum] = list.get(i).toString();
}
String outLine = composeLine(data, ctlInfo);
// write the line
pw.print(outLine);
pw.println();
}
}
}
private static String composeLine(String[] data, ControlInfo ctl) {
StringBuilder line = new StringBuilder();
String delim = ","
int elemCount = data.length;
for (int i = 0; i < elemCount; i++) {
if (i > 0)
line.append(delim);
if (data[i] != null && (data[i].contains("\n") || data[i].contains("\r") ||
data[i].contains("\r\n"))){
data[i] = data[i].replaceAll("(\\t|\\r?\\n)+", " ");
}
else {
line.append(data[i]);
}
}
return line.toString();
}
could you please let me know where I am wrong?
I found the issue, the code is good, the problem is in notepad++. If the character set in node pad ++ is Chinese(GB2312) then I am able to see the correct text. The note pad ++ is auto set GB2312 for two lines but for one line it is not doing auto set to GB2312.
everyone! I recently learned about variable byte encoding.
for example, if a file contains this sequence of number: 824 5 214577
applying variable byte encoding this sequence would be encoded as 000001101011100010000101000011010000110010110001.
Now I want to know how to write that in another file such that to produce a kind of compressed file from the original. and similarly how to read it. I'm using JAVA .
Have tried this:
LinkedList<Integer> numbers = new LinkedList<Integer>();
numbers.add(824);
numbers.add(5);
numbers.add(214577);
String code = VBEncoder.encodeToString(numbers);//returns 000001101011100010000101000011010000110010110001 into code
File file = new File("test.compressed");
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
out.writeBytes(code);
out.flush();
this just writes the binary representation into the file..and this is not what I'm expecting.
I have also tried this:
LinkedList<Integer> code = VBEncoder.encode(numbers);//returns linked list of Byte(i give its describtion later)
File file = new File("test.compressed");
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
for(Byte b:code){
out.write(b.toInt());
System.out.println(b.toInt());
}
out.flush();
// he goes the describtion of the class Byte
class Byte {
int[] abyte;
Byte() {
abyte = new int[8];
}
public void readInt(int n) {
String bin = Integer.toBinaryString(n);
for (int i = 0; i < (8 - bin.length()); i++) {
abyte[i] = 0;
}
for (int i = 0; i < bin.length(); i++) {
abyte[i + (8 - bin.length())] = bin.charAt(i) - 48;
}
}
public void switchFirst() {
abyte[0] = 1;
}
public int toInt() {
int res = 0;
for (int i = 0; i < 8; i++) {
res += abyte[i] * Math.pow(2, (7 - i));
}
return res;
}
public static Byte fromString(String codestring) {
Byte b = new Byte();
for(int i=0; i < 8; i++)
b.abyte[i] = (codestring.charAt(i)=='0')?0:1;
return b;
}
public String toString() {
String res = "";
for (int i = 0; i < 8; i++) {
res += abyte[i];
}
return res;
}
}
its prints this in the console:
6
184
133
13
12
177
this second attempt seems to work...the output file size is 6 bytes while for the first attemps it was 48 bytes.
but the problem in the second attempt is that I can't successfully read back the file.
InputStreamReader inStream = new InputStreamReader(new FileInputStream(file));
int c = -1;
while((c = inStream.read()) != -1){
System.out.println( c );
}
i get this:
6
184
8230
13
12
177
..so maybe I'm doing it the wrong way: expecting to receive some good advice from you. thanks!
It is solved; I was just not reading the file the right way:below is the right way:
DataInputStream inStream = null;
inStream = new DataInputStream(new BufferedInputStream(newFileInputStream(file)));
int c = -1;
while((c = inStream.read()) != -1){
Byte b = new Byte();
b.readInt(c);
System.out.println( c +":" + b.toString());
}
now I get this as the result:
6:00000110
184:10111000
133:10000101
13:00001101
12:00001100
177:10110001
Now the importance of writing the original sequence of integers into variable encoded bytes reduces the size of the file; if we normally write this sequence of integers in the file, its size would be 12 bytes (3 * 4 bytes). but now it is just 6 bytes.
int c = -1;
LinkedList<Byte> bytestream = new LinkedList<Byte>();
while((c = inStream.read()) != -1){
Byte b = new Byte();
b.readInt(c);
bytestream.add(b);
}
LinkedList<Integer> numbers = VBEncoder.decode(bytestream);
for(Integer number:numbers) System.out.println(number);
//
//here goes the code of VBEncoder.decode
public static LinkedList<Integer> decode(LinkedList<Byte> code) {
LinkedList<Integer> numbers = new LinkedList<Integer>();
int n = 0;
for (int i = 0; !(code.isEmpty()); i++) {
Byte b = code.poll();
int bi = b.toInt();
if (bi < 128) {
n = 128 * n + bi;
} else {
n = 128 * n + (bi - 128);
numbers.add(n);
n = 0;
}
}
return numbers;
}
I get back the sequence:
824
5
214577
I needed a method that would convert hex to ascii, and most seem to be a variation of the following:
public String hexToAscii(String hex) {
StringBuilder sb = new StringBuilder();
StringBuilder temp = new StringBuilder();
for(int i = 0; i < hex.length() - 1; i += 2){
String output = hex.substring(i, (i + 2));
int decimal = Integer.parseInt(output, 16);
sb.append((char)decimal);
temp.append(decimal);
}
return sb.toString();
}
The idea is to look at
hexToAscii("51d37bdd871c9e1f4d5541be67a6ab625e32028744d7d4609d0c37747b40cd2d");
If I print the result out, I get
-Í#{t7?`Ô×D?2^b«¦g¾AUM??Ý{ÓQ.
This is not the result I am needing though. A friend got the correct result in PHP which was the string reverse of the following:
QÓ{݇žMUA¾g¦«b^2‡D×Ô`7t{#Í-
There are clearly characters that his hexToAscii function is encoding whereas mine is not.
Not really sure why this is the case, but how can I implement this version in Java?
Assuming your input string is in, I would use a method like this
public static byte[] decode(String in) {
if (in != null) {
in = in.trim();
List<Byte> bytes = new ArrayList<Byte>();
char[] chArr = in.toCharArray();
int t = 0;
while (t + 1 < chArr.length) {
String token = "" + chArr[t] + chArr[t + 1];
// This subtracts 128 from the byte value.
int b = Byte.MIN_VALUE
+ Integer.valueOf(token, 16);
bytes.add((byte) b);
t += 2;
}
byte[] out = new byte[bytes.size()];
for (int i = 0; i < bytes.size(); ++i) {
out[i] = bytes.get(i);
}
return out;
}
return new byte[] {};
}
And then you could use it like this
new String(decode("51d37bdd871c9e1f4d5541be67a6ab625e"
+"32028744d7d4609d0c37747b40cd2d"))
How about trying like this:
public static void main(String[] args) {
String hex = "51d37bdd871c9e1f4d5541be67a6ab625e32028744d7d4609d0c37747b40cd2d";
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i+=2) {
String str = hex.substring(i, i+2);
output.append((char)Integer.parseInt(str, 16));
}
System.out.println(output);
}