I have java program which is running on mainframe z/os and is reading a EBCDIC file. Few of the lines in the file have multiple records separated by EBCDIC 'LF' X'025'. I am using Java readline and as expected it is reading the record till linefeed and discarding rest of the records. Besides parsing the big line into multiple records, is there any way to make the read methods split the line into multiple lines/records and return the same? If needed, I do have the option to change the new-line delimiter to any values.
Input:
10,IBM,ERWIN,BLACK,123,ABC(LF)10,IBM,JACK,ROSE,456
Expected output
10,IBM,ERWIN,BLACK,123,ABC
10,IBM,JACK,ROSE,456
Current Code:
public ArrayList<String> readMainframeFile()
{
//String DDNAME = ZFile.allocDummyDDName();
//System.out.println("The DDName is " + DDNAME);
//ZFile convout = new ZFile("//DD:CONVOUT", "wb,type=record,noseek");
//RecordReader reader=null;
try {
ZFile convin = new ZFile("//DD:CONVIN", "rb,type=record,noseek");
System.out.println("The DDName is" + convin.getLrecl());
byte[] recordBuf = new byte[convin.getLrecl()];
int bytesRead=0;
InputStream ins = null;
BufferedReader reader = null;
String temp=null;
ArrayList<String> lines = new ArrayList<String>();
while((bytesRead = convin.read(recordBuf)) > 0) {
//System.out.println("The number of bytes read is" + bytesRead);
try {
ins = new ByteArrayInputStream(recordBuf);
reader = new BufferedReader(new InputStreamReader(ins,Charset.forName("ibm500")));
temp=reader.readLine();
lines.add(temp);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
return lines;
} catch (ZFileException e) {
System.err.println(e.getMessage());
return null;
}
}
You're opening the file for QSAM binary I/O when you should be opening it as a text file stream.
ZFile convin = new ZFile("//DD:CONVIN", "r");
Then just read the records as you normally would with a stream. There's no need for an additional line reader. z/OS UNIX newlines are usually x'15' so you may need to change your linefeed character.
Related
I am new to Andriod dev and I am trying to build an app that connects to a Ble device which can be used to create a CSV file and store the values of any characteristic that has a notify property. I have implemented onCharacteristicChanged(..) and am able to receive the raw bytes once I am subscribed to the characteristic.
However, I don't know how I should go about creating a CSV file and writing these raw bytes until I have unsubscribed from the characteristic or disconnected from the device. Please help.
Edit:
I am trying to write it with CSVWriter and I call the following method every time I get a onCharacteristicChanged callback:
private void broadcastUpdate(final BluetoothGattCharacteristic characteristic, byte[] value){
if(isCharacteristicNotifiable(characteristic)){
String value_str = bytesToHex(value);
if(characteristic.getUuid().toString() == TX_CHARACTERISTIC){
value_str = bytestoformat(characteristic.getValue());
}
String[] line = value_str.split(" ");
Log.i("broadcastUpdate", value_str);
try {
CSVWriter writer = new CSVWriter(new FileWriter(csv, true));
writer.writeNext(line);
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
The number of bytes I get for each characteristic change is either 2 bytes or 4 bytes. So the CSV file should be printing 4 hex values in 1 line and leave 2 values blank when there are only 2 bytes of data.
However, if the first notification gives 2 bytes of data then my entire file only shows 2 bytes of data for every change (even if 4 bytes of data are being received after the first notification). And if the first notification has 4 bytes of data then I get what I want.
A CSV file can be created like any other file. First open a file to write to:
String header = "";
File file = new File("/storage/emulated/0/CharNotifyData.csv");
if (!file.exists()) {
file.createNewFile();
header = "Characteristic;Value\n";
}
FileWriter fw = new FileWriter(file.getAbsoluteFile(),true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(header);
Write your values like this:
bw.write(characteristicName + ";" + value + "\n");
Don't forget to close the file with:
bw.close();
Edit:
Try to differentiate between the two possible states. One way could look like this:
private void broadcastUpdate(final BluetoothGattCharacteristic characteristic, byte[] value){
if(isCharacteristicNotifiable(characteristic)){
String value_str = bytesToHex(value);
if(characteristic.getUuid().toString() == TX_CHARACTERISTIC){
value_str = bytestoformat(characteristic.getValue());
}
String[] line = value_str.split(" ");
String[] fullLine = new String[4];
for(int i = 0; i < 4; ++i){
if(i < line.length){
fullLine[i] = line[i];
}else{
fullLine[i] = "";
}
}
Log.i("broadcastUpdate", value_str);
try {
CSVWriter writer = new CSVWriter(new FileWriter(csv, true));
writer.writeNext(line);
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I read about someone having troubles with BufferedReader: the reader simply do not read the first lines. I have instead the opposite problem. For example, in a text file with 300 lines, it arrives at 200, read it half of it and then the following string is given null, so it stops.
private void readerMethod(File fileList) throws IOException {
BigInteger steps = BigInteger.ZERO;
BufferedReader br = new BufferedReader(new FileReader(fileList));
String st;
//reading file line by line
try{
while (true){
st = br.readLine();
if(st == null){
System.out.println("Null string at line " + steps);
break;
}
System.out.println(steps + " - " + st);
steps = steps.add(BigInteger.ONE);
}
}catch(Exception e){
e.printStackTrace();
}
finally{
try{
br.close();
}catch(Exception e){}
}
}
The output of the previous slice of code is as expected until it reaches line 199 (starting from 0). Consider a file with 300 lines.
...
198 - 3B02D5D572B66A82F9D21EE809320DB3E250C6C9
199 - 6E2C69795CB712C27C4097119CE2C5765
Null string at line 200
Notice that, all lines have the same length, so in this output line 199 is not even complete. I checked the file text, and it's correct: it contains all 300 lines and they are all of the same length. Also, in the text there are only capitals letters and numbers, as you can see.
My question is: how can i fix this? I need that the BufferedReader read all the text, not just a part of it.
As someone asked i add here the remaining part of the code. Please notice that all capital names are constant of various type (int, string etc).
This is the method that is called by the main thread:
public void init(){
BufferedWriter bw = null;
List<String> allLines = createRandomStringLines(LINES);
try{
String fileName = "SHA1_encode_text.txt";
File logFile = new File(fileName);
System.out.println(logFile.getCanonicalPath());
bw = new BufferedWriter(new FileWriter(logFile));
for(int i = 0; i < allLines.size(); i++){
//write file
String o = sha1FromString(allLines.get(i));
//sha1FromString is a method that change the aspect of the string,
//replacing char by char. Is not important at the moment.
bw.write(o + "\n");
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
bw.close();
}catch(Exception e){}
}
}
The method that create the list of random string is the following. "SYMBOLS" is just a String contains all avaiable chars.
private List<String> createRandomStringLines(int i) {
List<String> list = new ArrayList<String>();
while(i!=0){
StringBuilder builder = new StringBuilder();
int count = 64;
while (count-- != 0) {
int character = (int)(Math.random()*SYMBOLS.length());
builder.append(SYMBOLS.charAt(character));
}
String generatedString = builder.toString();
list.add(generatedString);
i--;
}
return list;
}
Note that, the file written is totally correct.
Okay, thanks to the user ygor, i manage to resolve it. The problem was that the BufferReader stars his job when the BufferWriter isn't closed yet. It was sufficient to move the command line that require the reader to work, after the bufferWriter.close() command.
I am trying to replace ? with - in my text document but just the ArrayList<String> is being written in the new file without all lines of the old one. How can I fix that?
File file = new File("D:\\hl_sv\\L09MF.txt");
ArrayList<String> lns = new ArrayList<String>();
Scanner scanner;
try {
scanner = new Scanner(file);
int lineNum = 0;
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
lineNum++;
if (line.contains("?")) {
line = line.replace("?", "-");
lns.add(line);
// System.out.println("I found it on line " + lineNum);
}
}
lines.clear();
lines = lns;
System.out.println("Test: " + lines);
FileWriter writer;
try {
writer = new FileWriter("D:\\hl_sv\\L09MF2.txt");
for (String str : lines) {
writer.write(str);
}
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I don't understand why you're storing the lines in a List to begin with. I would perform the transform and print while I read. You don't need to test for the presence of the ? (replace won't alter anything if it isn't present). And, I would also use a try-with-resources. Something like
File file = new File("D:\\hl_sv\\L09MF.txt");
try (PrintWriter writer = new PrintWriter("D:\\hl_sv\\L09MF2.txt");
Scanner scanner = new Scanner(file)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
writer.println(line.replace('?', '-'));
}
} catch (Exception e) {
e.printStackTrace();
}
Examine this code:
if (line.contains("?")) {
line = line.replace("?", "-");
lns.add(line);
}
You are only adding the current line (with the replacement) if it had a ? in it, ignoring other lines. Restructure it to always add the existing line.
if (line.contains("?")) {
line = line.replace("?", "-");
}
lns.add(line);
Additionally, the part
if (line.contains("?"))
scans line to look for a ?, and then the code
line.replace("?", "-");
does the same thing, but this time also replacing any ? with -. You may as well scan line just once:
lns.add(line.replace("?", "-"));
Note that creating an ArrayList just to hold the new lines wastes a fair amount of memory if the file is large. A better pattern would be to write each line, modified if necessary, right after you read in the corresponding line.
Within your while loop you have an if statement checking the line which adds the altered line to the array. You also need to add the unaltered lines to the array.
This should fix your issue:
int lineNum = 0;
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
lineNum++;
if (line.contains("?")) {
line = line.replace("?", "-");
lns.add(line);
// System.out.println("I found it on line " + lineNum);
}
else{
lns.add(line);
}
Previously, you were only adding the line to your ArrayList if it contained a "?" character. You need to add the line to the ArrayList whether or not it contains "?"
I would use a different approach if I'm trying to work on the functionality you want to implement, please check this approach and tell me if this helps you :)
public void saveReplacedFile() {
//1. Given a file in your system
File file = new File("D:\\hl_sv\\L09MF.txt");
try {
//2. I will read it, not necessarily with Scanner, but use a BufferedReader instead
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
//3. Define a variable that will hold the value of each line
String line = null;
//and also the information of your file
StringBuilder contentHolder = new StringBuilder();
//why not get your line separator based on your O.S?
String lineSeparator = System.getProperty("line.separator");
//4. Check your file line by line
while ((line = bufferedReader.readLine()) != null) {
contentHolder.append(line);
contentHolder.append(lineSeparator);
}
//5. By this point, your contentHolder will contain all the data of your text
//But it is still a StringBuilder type object, why not convert it to a String?
String contentAsString = contentHolder.toString();
//6. Now we can replace your "?" with "-"
String replacedString = contentAsString.replace("?", "-");
//7. Now, let's save it in a new file using BufferedWriter :)
File fileToBeSaved = new File("D:\\hl_sv\\L09MF2.txt");
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(fileToBeSaved));
bufferedWriter.write(replacedString);
//Done :)
} catch (FileNotFoundException e) {
// Exception thrown if the file does not exist in your system
e.printStackTrace();
} catch (IOException e) {
// Exception thrown due to an issue with IO
e.printStackTrace();
}
}
Hope this is helpful. Happy coding :)
If you can use Java 8 then your code can be simplified to
try (PrintStream ps = new PrintStream("D:\\hl_sv\\L09MF2.txt");
Stream<String> stream = Files.lines(Paths.get("D:\\hl_sv\\L09MF.txt"))) {
stream.map(line -> line.replace('?', '-')).forEach(ps::println);
} catch (IOException e) {
e.printStackTrace();
}
I have a bunch of strings that I'm writing to a file:
private void writeScoreToFile(BlastScore result)
{
try{
FileWriter fstream = new FileWriter(getFilesDir() + CaptureActivity.BLAST_SCORES,true);
BufferedWriter out = new BufferedWriter(fstream);
out.write(Integer.toString(result.getBlastScore()));
out.close();
}catch (Exception e){
System.err.println("Write Error: " + e.getMessage());
}
}
I would like to read it back in as a List.
private List<String> getArrayFromFile(String filename) throws IOException
{
FileReader fileReader = new FileReader(getFilesDir() + filename);
BufferedReader bufferedReader = new BufferedReader(fileReader);
List<String> lines = new ArrayList<String>();
String line = null;
while ((line = bufferedReader.readLine()) != null) {
lines.add(line);
}
bufferedReader.close();
return lines;
}
The list that is being written is:
100
96
100
96
100
When I print the List it looks like
10-28 21:22:31.130: I/System.out(936): Last Score: 1009610096100
Here is the code I am using to print it:
try {
List<String> blastScores = getArrayFromFile(CaptureActivity.BLAST_SCORES);
System.out.println("Last Score: " + blastScores.get(blastScores.size()-1));
} catch (IOException e) {
// TODO Auto-generated catch block
System.err.println("Read Error: " + e.getMessage());
}
I'm trying to get the n-1 element.
I'm not sure what I'm doing wrong.
When you are writing the Integers or Integer Strings you are not putting a new line character after each output. Hence, your file has only one line of data, which line you are getting as a continuous String...
To fix, add a line separator like write.newLine() in between separate write() calls.
The code which writes the scores uses
out.write(Integer.toString(result.getBlastScore()));
This means that if the method is called with scores 12, 100 and 2, your file will look like
121002
since you don't write any separator. How do you want to parse this into three numbers correctly?
Use a PrintWriter that wraps the BufferedWriter, and use its println method to write the score.
Note that writing the scores one by one by opening the file and closing it each time won't be very fast. BTW, using a BufferedWriter just to write a single integer won't gain any benefit. You also have bad exception handling : the streams and readers/writers should always be closed in a finally block.
In your writeScoreToFile function I don't see any new line or any sort of delimiter that would separate each score being written.
In that case your file would in fact contain 1009610096100 on a single line and the loop inside getArrayFromFile would only be executed once:
while ((line = bufferedReader.readLine()) != null) {
lines.add(line);
}
Therefore your List<String> only contains 1 element and the code blastScores.get(blastScores.size()-1) will get the last and only element, that obviously being 1009610096100.
I am trying to read values from a text file. There are 6 doubles on each line for the file.
I created a getBufReader method
public BufferedReader getBufReader(String filename, int rawName){
if(D) Log.i(TAG, "GETTING FILE");
BufferedReader bufReader = null;
// open the file for reading
InputStream instream = getResources().openRawResource(rawName);
// if file the available for reading
if (instream != null) {
// prepare the file for reading
InputStreamReader inputreader = new InputStreamReader(instream);
bufReader = new BufferedReader(inputreader);
}
// close the file again
try{instream.close();}
catch (Exception e) {
if(D) Log.e(TAG, "Unable to Close " + filename);}
return bufReader;
}
Each line in the file is supposed to be an entire row in my 2D array. I tried to get a line, tokenize it and put that in the array. But the program keeps crashing. The DDMS Log does does not produce a bunch or errors as I expect
public void getData(){
int rawName = R.raw.values_doubles;
BufferedReader reader_0 = getBufReader(strData2, rawName );
//2D array of x rows and y columns to store the data
//
double[][] Data_temp = new double[size_x][size_y];
String line = null;
StringTokenizer Strtoken;
for(i=0;i<size_x;i++){
try {line = reader_0.readLine();}catch (IOException e) {}
if(line != null){
Strtoken = new StringTokenizer(line);
for(j=0;j<size_y;j++){
if (Strtoken.hasMoreTokens()){
Data_temp[i][j] = Double.parseDouble(Strtoken.nextToken());
CommandsAdapter.add(""+Data_temp[i][j]+" ");
}}
}
CommandsAdapter.add("\n");}}
Please help
Also, I get errors if I don't surroung reader_0.readLine() with try/catch.
I would create a FileInputStream and a Buffered Reader. I am writing this from my lap top so I cannot test this code but this should give you a general idea (my first app saved data on seperate lines in a text file and I could read and write to it using this method)
NOTE this requires you to know how many lines are in your file
FileInputStream fis = new FileInputStream(file);
BufferedReader reader = new BufferedReader(fis);
Double myArray[][] = new Double [Text_File_Lines][6];
StringBuffer buffer = new StringBuffer();
int x = 0;
int y = 0;
while (reader.readLine() != -1) { //indicating end of file
while (reader.nextChar != '\n' ) { //indicating new line
while (reader.nextChar != ' ' ) { //indicating no space character
buffer.append(reader.nextChar());
}
Double[y][x] = Double.parseDouble(buffer.toString()); //Parse double and add it to array
buffer = null; //restore buffer to null
x++;
}
y++;
}
PLEASE NOTE THIS IS VERY SLOPPY CODE THAT ALMOST DEFINITELY WONT WORK this is just to get you started and I will post my working code when I get home from work.