Download file line by line java - java

I know this question might sound really basic for most of you. I need to download a large file from server. The first line of this file contains a time tag. I want to download entire file only if my time tag mismatches to that of file. For this I'm using the given code. However, I'm not sure if this actually prevents file from uselessly downloading entire file.
Please help me out !
public String downloadString(String url,String myTime)
{
try {
URL url1 = new URL(url);
URLConnection tc = url1.openConnection();
tc.setConnectTimeout(timeout);
tc.setReadTimeout(timeout);
BufferedReader br = new BufferedReader(new InputStreamReader(tc.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
if(line.contains(myTime))
{
Log.d("TIME CHECK", "Article already updated");
break;
}
sb.append(line+"\n");
}
br.close();
return sb.toString();
}
catch(Exception e)
{
Log.d("Error","In JSON downloading");
}
return null;
}

No, there is no easy way to control exactly to the last byte what will be downloaded. Even at the Java level you are involving a BufferedReader, which will obviously download more than you ask for, buffering it. There are other buffers as well, including at the OS level, which you cannot control. The proper technique to download only new files with HTTP is to use the IfModifiedSince header.

Your code won't download the whole file but as the BufferedReader has a default buffer size of 8192 you will read at least that many characters.

You can go byte-by-byte or chunk-by-chunk if it is the size
BufferedInputStream in = new BufferedInputStream(url).openStream())
byte data[] = new byte[1024];
int count;
while((count = in.read(data,0,1024)) != -1)
{
out.write(data, 0, count);
}
Check this question please
How to download and save a file from Internet using Java?

Related

Hebrew rendering in website

I am working on a product which has an internet "Admin Panel" - Somewhere the user can see information about the product. One of the minimal requirements is that the website has both English and Hebrew Version. So what is the problem? The problem is that some of the characters look like this, But they should look like this.
When I get a request from a browser I read an HTML file using this code (JAVA):
public static String loadPage(String page, String lang) {
Path path = Paths.get(System.getProperty("user.dir"), "htmlTemplate", lang, page + ".html");
try (BufferedReader br = Files.newBufferedReader(path)) {
StringBuilder website = new StringBuilder();
String currentLine;
while ((currentLine = br.readLine()) != null) {
website.append(currentLine);
}
return website.toString();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
(Thanks to Jon Skeet for helpig with reading it as UTF-8), After I read the file I am replacing some of the comments to with the correct data (For example: I have a comment like this: <!--username--> and I replace it with "Itay"), After the replacing I just send the response.
The server itself is hosted using sun's HttpServer.
I also made sure to do these things:
I saved the html file as UTF-8
In the html file there is this meta tag: <meta charset="UTF-8">"
One of the response headers is: Content-Type=text/html;charset=utf-8
By the way i am using Chrome.
So I hope I gave enough details about my problem and if you need more feel free to tell me!
(I also hope I posted the question with the right tags and title)
Basically, don't use FileReader. It always uses the platform-default encoding, which may well not be appropriate for this file.
If you're using a modern version of Java, it's better to use:
Path path = Paths.get(System.getProperty("user.dir"), "htmlTemplate", lang, page + ".html");
br = Files.newBufferedReader(path);
That will read in UTF-8 by default - if you wanted a different charset, you can specify it as another argument to newBufferedReader.
I'd also advise you to use a try-with-resources statement to get rid of all the cruft with a manual finally block:
Path path = Paths.get(System.getProperty("user.dir"), "htmlTemplate", lang, page + ".html");
try (BufferedReader br = Files.newBufferedReader(path)) {
StringBuilder website = new StringBuilder();
String currentLine;
while ((currentLine = br.readLine()) != null) {
website.append(currentLine);
}
return website.toString();
}
That will remove all line breaks, mind you. (Note that I've used StringBuilder to avoid performance issues from repeated string concatenation...)
You need to tell your FileReader to read as UTF8.
In the end i found that i realy had a problem reading as UTF-8 but the other problem was thats I have not sent it back as UTF-8 So this is how i sent it:
public void end(HttpExchange t, String response, long tStart, int status) throws IOException {
try {
String temp = convertToUTF8(response);
t.sendResponseHeaders(status, temp.length());
OutputStream os = t.getResponseBody();
OutputStream bout= new BufferedOutputStream(os);
OutputStreamWriter out = new OutputStreamWriter(bout, "UTF-8");
out.write(response);
out.flush();
out.close();
}catch (UnsupportedEncodingException e) {
System.out.println("This VM does not support the UTF-8 character set.");
}catch (IOException e) {
System.out.println(e.getMessage());
}
long tEnd = System.currentTimeMillis();
long tDelta = tEnd - tStart;
System.out.println("Done handling request! Time took: " + tDelta);
}
Again thank you Jon Skeet for yor answer it was very helpfull!
Path path = Paths.get(System.getProperty("user.dir"), "htmlTemplate", lang, page + ".html");
try (BufferedReader br = Files.newBufferedReader(path)) {
StringBuilder website = new StringBuilder();
String currentLine;
while ((currentLine = br.readLine()) != null) {
website.append(currentLine);
}
return website.toString();
}
(This is how to read the file as UTF-8 using his way)

Android BufferedReader does not read the whole response

I have a problem with reading a ULR response. On Android it only reads around the half of the response.
If I use the same code in a normal Java project everything works fine.
try {
String _output = null;
URL url = new URL("http://example.com");
BufferedReader buffer = new BufferedReader(new InputStreamReader(url.openStream()));
StringBuilder everything = new StringBuilder();
String line;
while ((line = buffer.readLine()) != null) {
everything.append(line);
}
_output = everything.toString();
buffer.close();
System.out.print(_output);
} catch (IOException e) {
e.printStackTrace();
}
How do you know that it's only half of the response? If you rely on what is printed with System.out.println() then you should be aware that Logcat has a limitation that prevents it from printing more than 4,000 characters. Anything after that is truncated. To check how much of the response you have, you could print everything.length()first, ot see if you are in that situation.
You can look at this existing question on SO for reference, but there are many others.

Download a text file from the web - Android/ Java

I'm trying to get save a text file from the internet into a folder in my res directory (res/files) so I can then read and interpret it. My android manifest has set the appropiate permissions but when I test it in the simulator it fails.
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
Here's the method to get the file:
public void getTextFile(){
String path ="http://hullmc.org.uk/cjvize/test.txt";
URL u = null;
try {
u = new URL(path);
BufferedReader in = new BufferedReader(new InputStreamReader(u.openStream()));
int i = 0;
String replicated = "";
do{
String str = in.readLine();
replicated = replicated + "/n" + str;
i++;
}while(i<85);
in.close();
}
catch(Exception e){
welcome.setText("Failed");
}
}
Can anyone suggest why this is not working? Many thanks!
This is working fine for me :
Use of class variable for View and Activity allow to keep code centralaized and shared, passing view as parameter, updated in constructor :)
1) Code to store the file locally
View newReport;
Activity reportActivity;
private void downloadFile(String fileUrl, String fileName) {
try{
InputStream is = (InputStream) new URL(fileUrl).getContent();
FileOutputStream output = reportActivity.openFileOutput(fileName, newReport.getContext().MODE_PRIVATE);
byte data[] = new byte[1024];
int count;
while ((count = is.read(data)) != -1)
output.write(data, 0, count);
output.flush();
output.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
It saves the file on the internal storage.
Then to save a file from URL, just call:
downloadFile(myFileUrl, mySaveToFileName);
And to list your local files available:
String[] fileList = newReport.getContext().fileList();
for (String s : fileList){
System.out.println("File found : "+s);
}
Note: you do not require to save it locally to read it. If you prefer just to read it (to extract some info), let me know.
2) Code to "read and save to database", this should resolve:
// After InputStream declaration:
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String inputLine;
while ((inputLine = in.readLine()) != null)
{
//TODO Update database row concatenating inputLine to existing text value.
}
in.close();
in=null;
is.close();
you can't save into the resource folder of your app. you can't even store files into the assets folder.
there aren't even such folders when you install the app - they are all zipped into the APK . the res folder is a special one too, because each file there also creates a constant in the "R.java" file, so that it would be easier to reach and use. you can't reach such a thing when it's dynamic...
what you can do is to choose the right folder for you (read here), and download the file into there, using something like this :
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(fullFilePath);
byte data[] = new byte[1024];
int count;
while ((count = input.read(data)) != -1)
output.write(data, 0, count);
//todo close streams and handle exceptions
if you use Apache commons library, you could minimize the code to just one line:
IOUtils.copy(new BufferedInputStream(url.openStream()), new FileOutputStream(fullFilePath));

You Tube downloader

I tried to download youtube video (using the same link like keepvid). The file that I got is 4kB larger than one downloaded via browser, and it cannot be played. Can anybody tell me why,and what i do wrong?
Additionally, when I print both files line by line, they show equal data. Code that I used for downloading is below.
Thanks.
try {
URL hr= new URL("link");
URLConnection conn= hr.openConnection();
conn.setRequestProperty("Uzer-Agent", "Mozilla/5.0");
conn.connect();
BufferedReader br=new BufferedReader(new InputStreamReader(conn.getInputStream()));
File file=new File("video.flv");
PrintWriter pw=new PrintWriter(new FileWriter(file));
String line="";
while((line=br.readLine())!=null){
System.out.println(line);
pw.println(line);
}
pw.close();
} catch (Exception e){}
yeah, although reading might be done with br.readLine() (not sure, I'd read it with br.read( char[ 4096 ], off, len ), but writing with pw.println is definitely wrong, as it adds a line-break at the end of each line - something you don't want to see in a binary file.
I'd put it like
char[] buff = new char[ 4096 ];
int offset = 0;
while( -1 != br.read( buff, offset, 4096 ) ){
pw.write( buff );
offset += 4096;
}
You can also use Input/Output-Streams here, as you don't need to do a character-conversions.
You can't read binary files (like flv) as if they were text files, using readLine() and so on. You must use the unformatted read() and write() methods in InputStream and OutputStream respectively.

Prepend lines to file in Java

Is there a way to prepend a line to the File in Java, without creating a temporary file, and writing the needed content to it?
No, there is no way to do that SAFELY in Java. (Or AFAIK, any other programming language.)
No filesystem implementation in any mainstream operating system supports this kind of thing, and you won't find this feature supported in any mainstream programming languages.
Real world file systems are implemented on devices that store data as fixed sized "blocks". It is not possible to implement a file system model where you can insert bytes into the middle of a file without significantly slowing down file I/O, wasting disk space or both.
The solutions that involve an in-place rewrite of the file are inherently unsafe. If your application is killed or the power dies in the middle of the prepend / rewrite process, you are likely to lose data. I would NOT recommend using that approach in practice.
Use a temporary file and renaming. It is safer.
There is a way, it involves rewriting the whole file though (but no temporary file). As others mentioned, no file system supports prepending content to a file. Here is some sample code that uses a RandomAccessFile to write and read content while keeping some content buffered in memory:
public static void main(final String args[]) throws Exception {
File f = File.createTempFile(Main.class.getName(), "tmp");
f.deleteOnExit();
System.out.println(f.getPath());
// put some dummy content into our file
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f)));
for (int i = 0; i < 1000; i++) {
w.write(UUID.randomUUID().toString());
w.write('\n');
}
w.flush();
w.close();
// append "some uuids" to our file
int bufLength = 4096;
byte[] appendBuf = "some uuids\n".getBytes();
byte[] writeBuf = appendBuf;
byte[] readBuf = new byte[bufLength];
int writeBytes = writeBuf.length;
RandomAccessFile rw = new RandomAccessFile(f, "rw");
int read = 0;
int write = 0;
while (true) {
// seek to read position and read content into read buffer
rw.seek(read);
int bytesRead = rw.read(readBuf, 0, readBuf.length);
// seek to write position and write content from write buffer
rw.seek(write);
rw.write(writeBuf, 0, writeBytes);
// no bytes read - end of file reached
if (bytesRead < 0) {
// end of
break;
}
// update seek positions for write and read
read += bytesRead;
write += writeBytes;
writeBytes = bytesRead;
// reuse buffer, create new one to replace (short) append buf
byte[] nextWrite = writeBuf == appendBuf ? new byte[bufLength] : writeBuf;
writeBuf = readBuf;
readBuf = nextWrite;
};
rw.close();
// now show the content of our file
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
You could store the file content in a String and prepend the desired line by using a StringBuilder-Object. You just have to put the desired line first and then append the file-content-String.
No extra temporary file needed.
No. There are no "intra-file shift" operations, only read and write of discrete sizes.
It would be possible to do so by reading a chunk of the file of equal length to what you want to prepend, writing the new content in place of it, reading the later chunk and replacing it with what you read before, and so on, rippling down the to the end of the file.
However, don't do that, because if anything stops (out-of-memory, power outage, rogue thread calling System.exit) in the middle of that process, data will be lost. Use the temporary file instead.
private static void addPreAppnedText(File fileName) {
FileOutputStream fileOutputStream =null;
BufferedReader br = null;
FileReader fr = null;
String newFileName = fileName.getAbsolutePath() + "#";
try {
fileOutputStream = new FileOutputStream(newFileName);
fileOutputStream.write("preappendTextDataHere".getBytes());
fr = new FileReader(fileName);
br = new BufferedReader(fr);
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null) {
fileOutputStream.write(("\n"+sCurrentLine).getBytes());
}
fileOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
if (br != null)
br.close();
if (fr != null)
fr.close();
new File(newFileName).renameTo(new File(newFileName.replace("#", "")));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

Categories