Scenario: I have code that calls a soap web service, gets an attachment which is a zip file. Then unzips it, goes through all the files, gets the one file I want, which is a csv file, and gets the content of the csv file:
public static void unzipTry2(AttachmentPart att) throws IOException, SOAPException {
try (ZipInputStream zis = new ZipInputStream(att.getRawContent())) {
byte[] buffer = new byte[1024];
for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
if (zipEntry.isDirectory()) {
continue;
}
if (!zipEntry.getName().equals("FileIwant.csv")) {
continue; //if it's not the file I want, skip this file
}
System.out.println(zipEntry.getName());
for (int len = zis.read(buffer); len > 0; len = zis.read(buffer)) {
//System.out.write(buffer, 0, len);
String testString = new String(buffer,0,len);
processCSVString(testString);
}
}
}
}
It works just fine. However the CSV file that I am getting only contains one line, which is expected now, but in the future it may contain multiple lines. Since it's a CSV file, I need to parse LINE BY LINE. This code also has to work for the case where the CSV file contains multiple lines, and that is where I am not sure if it works since there is no way to test that (I don't control the input of this method, that all comes from the web service).
Can you tell me if the inner for loop reads the content of the file LINE by LINE? :
for (int len = zis.read(buffer); len > 0; len = zis.read(buffer)) {
//System.out.write(buffer, 0, len);
String testString = new String(buffer,0,len);
processCSVString(testString);
}
BufferedReader is the Java "thing" which can read a Reader line-by-line. And the glue what you need is InputStreamReader. Then you can wrap the ZipInputStream as
BufferedReader br=new BufferedReader(new InputStreamReader(zis))
(preferably in a try-with-resources block), and the classic loop for reading from a BufferedReader looks like this:
String line;
while((line=br.readLine())!=null){
<process one line>
}
Related
I have a Zip file that I am trying to read. I do not want to use a ZipFile because in the future, I would like to do this for data that is not from a file.
This is what I have tried so far. Instead of printing the contents of res00000.dat, it prints an empty line. I do not know how to fix this
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
if (!zipEntry.getName().equals("res00000.dat")) {
zipInputStream.closeEntry();
continue;
}
}
int len;
ByteArrayOutputStream byteArrayOutputStream = new ByterrayOutputStream();
byte[] buffer = new byte[1024];
while ((len = zipInputStream.read(buffer)) > 0) {
byteArrayOutputStream.write(buffer, 0, len);
}
String xml = byteArrayOutputStream.toString();
System.out.println(xml);
zipInputStream.closeEntry();
zipInputStream.close();
return null;
My ZIP file has only two files in it. It is a Blackboard Test bank file that I'm attempting to parse:
Zip file
+-imsmanifest.xml
+-res00000.dat
Can someone please help?
You code currently doesn't handle a missing entry. It just silently scrolls to the end of a ZipInputStream so there is no way to tell what's happening. You could do following to get exception when an entry identified by name is missing:
public String readEntry(ZipInputStream in, String name) {
while ((zipEntry = in.getNextEntry()) != null) {
if (zipEntry.getName().equals(name)) {
return readXml(zipInputStream);
}
}
throw new IllegalStateException(name + " not found inside ZIP");
}
You will most likely observe above IllegalStateException now for missing res00000.dat.
Do note that there is no reason to call closeEntry() manually when scrolling the ZipInputStream as getNextEntry() already does it under the hood. From JDK 11 source code:
public ZipEntry getNextEntry() throws IOException {
ensureOpen();
if (entry != null) {
closeEntry();
}
...
I have a method to copy the entire file from one destination to another destination using buffer:
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
The file is in csv format:
"2280B_TJ1400_001","TJ1400_Type-7SR","192.168.50.76","Aries SDH","6.0","192.168.0.254",24,"2280B Cyberjaya","Mahadzir Ibrahim"
But as you can see it has quotes inside it. Is it possible remove them by based on my exisitng code???
Output should be like this:
2280B_TJ1400_001,TJ1400_Type-7SR,192.168.50.76,Aries SDH,6.0,192.168.0.254,24,2280B Cyberjaya,Mahadzir Ibrahim
If you use a BufferedReader you can use the readLine() function to read the contents of the file as a String. Then you can use the normal functions on String to manipulate it before writing it to the output. By using an OutputStreamWriter you can write the Strings directly.
An advantage of the above is that you never have to bother with the raw bytes, this makes your code easier to read and less prone to mistakes in special cases.
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(src)));
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(dest));
String line;
while ((line = in.readLine()) != null) {
String stringOut = line.replaceAll("\"", "");
out.write(stringOut);
}
in.close();
out.close();
Note that this removes all " characters, not just the ones at the start and end of each String. To do that, you can use a StringTokenizer, or a more complex replace.
Not sure it's a good idea or not, but you can do something like :
while ((len = in.read(buf)) > 0) {
String temp = new String(buf);
temp = temp.replaceAll("\"","");
buf = temp.getBytes();
len = temp.length();
out.write(buf, 0, len);
}
For me, I would read all the file before, in a String, and then strip out the ' " ' in the string. Then write it to the dest file.
Read the file in a string
I found this simple solution. This may not be the best depending on your level of error catching you need.But it's working enough ;)
String content = new Scanner(new File("filename")).useDelimiter("\\Z").next();
Stripout the ' " '
content = content.replaceAll('"', "");
Write it to dest file from here
Files.write(Paths.get("./duke.txt"), msg.getBytes());
This is for java 7+.
Did not test it but it should work !
Not necessarily good style, filtering quotes in binary data, but very solid.
Wrap the original InputStream with your own InputStream, filtering out the double quote.
I have added a quirk: in MS Excel a quoted field may contain a quote, which then is self-escaped, represented as two double quotes.
InputStream in = new UnquotingInputStream(new FileInputStream(src));
/**
* Removes ASCII double quote from an InputStream.
* Two consequtive quotes stand for one quote: self-escaping like used
* by MS Excel.
*/
public class UnquotingInputStream extends InputStream {
private final InputStream in;
private boolean justHadAQuote;
public UnquotingInputStream(InputStream in) {
this.in = in;
}
#Override
public int read() throws IOException {
int c = in.read();
if (c == '\"') {
if (!justHadAQuote) {
justHadAQuote = true;
return read(); // Skip quote
}
}
justHadAQuote = false;
return c;
}
}
Works for all encodings that use ASCII as subset. So not: UTF-16 or EBCDIC.
I have a text file with the following contents:
one
two
three
four
I want to access the string "three" by its position in the text file in Java.I found the substring concept on google but unable to use it.
so far I am able to read the file contents:
import java.io.*;
class FileRead
{
public static void main(String args[])
{
try{
// Open the file that is the first
// command line parameter
FileInputStream fstream = new FileInputStream("textfile.txt");
// Get the object of DataInputStream
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
// Print the content on the console
System.out.println (strLine);
}
//Close the input stream
in.close();
}catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
}
}
I want to apply the substring concept to the file.It asks for the position and displays the string.
String Str = new String("Welcome to Tutorialspoint.com");
System.out.println(Str.substring(10, 15) );
If you know the byte offsets within the file that you are interested in then it's straightforward:
RandomAccessFile raFile = new RandomAccessFile("textfile.txt", "r");
raFile.seek(startOffset);
byte[] bytes = new byte[length];
raFile.readFully(bytes);
raFile.close();
String str = new String(bytes, "Windows-1252"); // or whatever encoding
But for this to work you have to use byte offsets, not character offsets - if the file is encoded in a variable-width encoding such as UTF-8 then there's no way to seek directly to the nth character, you have to start at the top of the file and read and discard the first n-1 characters.
look for \r\n (linebreaks) in your text file. This way you should be able to count the rows containing your string.
your file in reality looks like this
one\r\n
two\r\n
three\r\n
four\r\n
You seem to be looking for this. The code I posted there works on the byte level, so it may not work for you. Another option is to use the BufferedReader and just read a single character in a loop like this:
String getString(String fileName, int start, int end) throws IOException {
int len = end - start;
if (len <= 0) {
throw new IllegalArgumentException("Length of string to output is zero or negative.");
}
char[] buffer = new char[len];
BufferedReader reader = new BufferedReader(new FileReader(fileName));
for (int i = 0; i < start; i++) {
reader.read(); // Ignore the result
}
reader.read(buffer, 0, len);
return new String(buffer);
}
I mean , I want to delete line from my text on android. How can I delete?
I do not want to read one txt and create another with removing line. I want to delete line from my existing txt.
thanks.
This is a pretty tricky problem, despite it looking a trivial one. In case of variable lines length, maybe your only option is reading the file line by line to indentify offset and length of the target line. Then copying the following portion of the file starting at offset, eventually truncating the file lenght to its original size minus the the target line's length. I use a RandomAccessFile to access the internal pointer and also read by lines.
This program requires two command line arguments:
args[0] is the filename
args[1] is the target line number (1-based: first line is #1)
public class RemoveLine {
public static void main(String[] args) throws IOException {
// Use a random access file
RandomAccessFile file = new RandomAccessFile(args[0], "rw");
int counter = 0, target = Integer.parseInt(args[1]);
long offset = 0, length = 0;
while (file.readLine() != null) {
counter++;
if (counter == target)
break; // Found target line's offset
offset = file.getFilePointer();
}
length = file.getFilePointer() - offset;
if (target > counter) {
file.close();
throw new IOException("No such line!");
}
byte[] buffer = new byte[4096];
int read = -1; // will store byte reads from file.read()
while ((read = file.read(buffer)) > -1){
file.seek(file.getFilePointer() - read - length);
file.write(buffer, 0, read);
file.seek(file.getFilePointer() + length);
}
file.setLength(file.length() - length); //truncate by length
file.close();
}
}
Here is the full code, including a JUnit test case. The advantage of using this solution is that it should be fully scalable with respect to memory, ie since it uses a fixed buffer, its memory requirements are predictable and don't change according to the input file size.
Try storing file into a String buffer replace what you intend to replace, then replace the contents of the file entirely.
You can delete a line by copying the rest of the data in the file, then flushing the file and finally writing the copied data.Thr following code searches for the string to be deleted and skips the code to copy in a stringBuider . The contents of stringBuilder are copied to the same file after flushing
try {
InputStream inputStream = openFileInput(FILENAME);
FileOutputStream fos = openFileOutput("temp", Context.MODE_APPEND);
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String receiveString = "";
String deleteString = "<string you want to del>";
StringBuilder stringBuilder = new StringBuilder();
while ((receiveString = bufferedReader.readLine()) != null) {
if (!reciveString.equals(deleteline)) {
stringBuilder.append(receiveString);
}
}
fos.flush();
fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(stringBuilder.toString().getBytes());
fos.close();
inputStream.close();
}
In the last section of the code I print what the Reader gives me. But its just bogus, where did I go wrong?
public static void read_impl(File file, String targetFile) {
// Create zipfile input stream
FileInputStream stream = new FileInputStream(file);
ZipInputStream zipFile = new ZipInputStream(new BufferedInputStream(stream));
// Im looking for a specific file/entry
while (!zipFile.getNextEntry().getName().equals(targetFile)) {
zipFile.getNextEntry();
}
// Next step in api requires a reader
// The target file is a UTF-16 encoded text file
InputStreamReader reader = new InputStreamReader(zipFile, Charset.forName("UTF-16"));
// I cant make sense of what this print
char buf[] = new char[1];
while (reader.read(buf, 0, 1) != -1) {
System.out.print(buf);
}
}
I'd guess that where you went wrong was believing that the file was UTF-16 encoded.
Can you show a few initial byte values if you don't decode them?
Your use of a char array is a bit pointless, though at first glance it should work. Try this instead:
int c;
while ((c = reader.read()) != -1) {
System.out.print((char)c);
}
If that does not work either, then perhaps you got the wrong file, or the file does not contain what you think it does, or the console can't display the characters it contains.