Up till early this year the US Treasury web site posted monthly US Receipts and Outlays data in txt format. It was easy to write a program to read and store the info. All I use were:
URL url = new URL("https://www.fiscal.treasury.gov/fsreports/rpt/mthTreasStmt/mts1214.txt")
URLConnection connection.openConnection();
InputStream is = connection.getInputStream();
Then I just read the InputStream into a local file.
Now when I try same code, for May, I get an InputStream with nothing in it.
Just clicking on "https://www.fiscal.treasury.gov/fsreports/rpt/mthTreasStmt/mts0415.xlsx" opens an excel worksheet (the download path has since changed).
Which is great if you don't mind clicking on each link separately ... saving the file somewhere ... opening it manually to enable editing ... then saving it again as a real .xlsx file (because they really hand you an .xls file.)
But when I create a URL from that link, and use it to get an InputStream, the is empty. I also tried url.openStream() directly. No different.
Can anyone see a way I can resume using a program to read the new format?
In case its of interest I now use this code to write the stream to the file bit by bit... but there are no bits, so I don't know if it works.
static void copyInputStreamToFile( InputStream in, File file ) {
try {
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
System.out.println("reading: " + in.read(buf));
//This is what tells me it is empty, i.e. the loop below is ignored.
int len;
while((len=in.read(buf))>0){
out.write(buf,0,len);
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Any help is appreciated.
Related
I'm trying to write an InputStream that is an mp4 that I get from calling an external SOAP service, when I do so, it always generates this tmp files for my chosen temporary directory(java.io.tmpdir) that aren't removable and stay after the writing is done.
Writing images that I also get from the SOAP service works normal without the permanent tmp on the directory. I'm using java 1.8 SpringBoot
tmp files
This is what I'm doing:
File targetFile = new File("D:/archive/video.mp4");
targetFile.getParentFile().mkdirs();
targetFile.setWritable(true);
InputStream inputStream = filesToWrite.getInputStream();
OutputStream outputStream = new FileOutputStream(targetFile);
try {
int byteRead;
while ((byteRead = inputStream.read()) != -1) {
outputStream.write(byteRead);
}
} catch (IOException e) {
logger.fatal("Error# SaveFilesThread for guid: " + guid, e);
}finally {
try {
inputStream.close();
outputStream.flush();
outputStream.close();
}catch (Exception e){
e.printStackTrace();
}
also tried:
byte data[] = IOUtils.toByteArray(inputStream);
Path file = Paths.get("video.mp4");
Files.write(file, data);
And from apache commons IO:
FileUtils.copyInputStreamToFile(initialStream, targetFile);
When your code starts, the damage is already done. Your code is not the source of the temporary files (It's.. a ton of work for something that could be done so much simpler, though, see below), it's the framework that ends up handing you that filesToWrite variable.
It is somewhat likely that you can hook in at an earlier point and get the raw inputstream representing the socket or HTTP connection, and start saving the files straight from there. Alternatively, Perhaps filesToWrite has a way to get at the files themselves, in which case you can just move them into place instead of copying them over.
But, your code to do this is a mess, it has bad exception handling, and leaks memory, and is way too much code for a simple job, and is possibly 2000x to 10000x slower than needed depending on your harddisk (I'm not exaggerating, calling single-byte read() on unbuffered streams is thousands of times slower!)
// add `throws IOException` to your method signature.
// it saves files, it's supposed to throw IOException,
// 'doing I/O' is in the very definition of your method!
try (InputStream in = filesToWrite.getInputStream();
OutputStream out = new FileOutputStream(targetFile)) {
in.transferTo(out);
}
That's it. That solves all the problems - no leaks, no speed loss, tiny amount of code, fixes the deplorable error handling (which, here, is 'log something to the log, then print something to standard out, then potentially leak a bunch of resources, then don't tell the calling code anything went wrong and return exactly as if the copy operation succeeded).
So I have this code which reads the proper installer file from disk (tar.gz, exe or dmg), and streams it to the user (code below). The installers are actually archives, which can be extracted and setup can be ran manually (this is specific for Windows, Mac installer needs to be mounted, Unix installer also needs to be extracted)
InputStream in = null;
OutputStream out = null;
byte[] buffer = new byte[16384];
try {
String bundle = ServletRequestUtils.getRequiredStringParameter(request, "bundle");
String installerPath = constructFilePath(bundle);
File installer = new File(installerPath);
if(!installer.exists()){
logger.error("Cannot read installer file");
response.sendRedirect("/somewhere");
}else{
in = new FileInputStream(installer);
response.setContentType(getBundleContentType(bundle)); //application/octet-stream or application/x-gzip or application/x-apple-diskimage
response.setHeader("Pragma", "private");
response.setHeader("Cache-Control", "private, must-revalidate");
response.addHeader("Content-Disposition", "attachment;filename="+getBundleFileName(bundle)); //Setting new file name
out = new BufferedOutputStream(response.getOutputStream());
while((in.read(buffer)) != -1)
out.write(buffer);
}
} catch (Exception e) {
logger.error("Exception downloading installer file, reason: " + e);
response.sendRedirect("/somewhere");
} finally {
if(in != null){
in.close();
}
if(out != null){
out.flush();
out.close();
}
}
return null;
I'll take the Windows (.exe) installer as an example. Previously, when I had the code to redirect to http:///somepath/installer.exe for the download, the file would've been downloaded and I was able to extract it with 7zip, but now, when I try to extract it with 7zip, I'm getting :
Cannot open file as archive.
However, I am able to double-click the .exe and successfully do the install. I am also able to extract it using winRAR as well.
Same thing happened with the Unix installer. When I download it to a Unix machine and try to extract it (by right-click "Extract here") I'm getting this error:
gzip: stdin: decompression OK, trailing garbage ignored
/bin/gtar: Child returned status 2
/bin/gtar: Error is not recoverable: exiting now
However, I am able to open it with "ark" and properly extract its contents.
I should also point out that the bytes of the files do not match after a download (the downloaded one compared to the one on the filesystem, which should be the same).
Am I missing something?
You could try write exactly the same data you read:
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
It is because you are writing the whole buffer.
Imagine the file was 16385 bytes.
The first in.read(buffer) would fill up the whole buffer and return 16384. You will then write the whole buffer. The second time, it will read one byte and again, you will write the whole buffer.
Someone has beaten me to it, but I was going to add that you could use IOUtils to do this...
http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html
For example IOUtils.copy(in, out)
I am using Kryo to save binary files of user data. The user can open one of their files in my application. I'm not sure if I have a clean approach to detecting whether they tried to open a file of some other type.
Right now, I'm writing a simple FileHeader object to the file before the user's data. The file header has info about what version of the app saved the file.
public void write (UserProject project, File file) throws FileNotFoundException {
OutputStream outputStream = new DeflaterOutputStream(new FileOutputStream(file));
Output output = new Output(outputStream);
kryo.writeObject(output, new FileHeader());
kryo.writeObject(output, project);
output.close();
}
So when I load a file, I can try to deserialize the file header and the user project and catch any Exception that might occur. But doing a catch-all block could hide certain issues I could perhaps react to in a more elegant way that simply showing the user an error no matter the exception. Here's what I'm doing now:
public Project read (File file) throws FileNotFoundException, FileVersionException, UnreadableException {
InputStream inputStream = new InflaterInputStream(new FileInputStream(file));
Input input = new Input(inputStream);
try {
FileHeader fileHeader = kryo.readObject(input, FileHeader.class);
if (fileHeader.fileVersion > CURRENT_FILE_VERSION)
throw new FileVersionException(/* */);
Project project = kryo.readObject(input, Project.class);
return project;
} catch (Exception e){
if (DEBUG) e.printStackTrace();
throw new UnreadableException(e); //caller will show user error msg
} finally {
input.close();
}
}
I suppose there's also a very tiny (infinitesimal?) chance that some file actually loads without throwing an exception, in which case a very unexpected error could happen elsewhere in my application. Not sure if I should worry about this...a user should not expect to open an incorrect file type and have it work correctly.
You could use magic numbers, a set of bytes that describes the type of file. Like .jpg, .pdf, .wav, etc. all have a few bytes at the beginning of each file, so even if these types are saved with different extensions you can check to see if the file's magic number is OK.
Magic Number Description
However, if you're serializing and deserializing you may have to tack on some additional data to the file after serializing and remove it before deserializing.
I'm trying to create copy of a mp3 file.This I need to trim that mp3 file.So using input,output stream can be used to this I guess.Can the normal text file type of copying will be able to create a file that could be played .Someone with good knowledge of file handling in java help me in this.
MP3 file is binary file. So as long as you copy MP3 using binary file operations copy will succeed.
However to trim an MP3 file, you need to be aware of MP3 file structure. MP3 file consists of series of MP3 frames. Each frame starts with a MP3 header and followed by data. MP3 frame header contains information, using which you can find frame length.
More details on MP3 header at http://www.id3.org/mp3Frame
So as long as you copy at integral number of frames, you should be okay. Even otherwise, decoders will ignore incomplete frame.
Below code is a solution to copy an mp3 file or everything else. I have never experienced the trimming part. However, I think it is logically possible to trim your file just by specifying the amount of buffer you need.)
Actually dst is the name of the copied file in the directory.
private void copyFile(String src, String dst) {
FileInputStream inputStream; // create an input stream
FileOutputStream outputStream; // create an output stream
try {
inputStream = new FileInputStream(src); // create object
outputStream = openFileOutput(dst, Context.MODE_PRIVATE); // save your file in private mode, which makes it inaccessible by other applications
int bufferSize;
byte[] bufffer = new byte[512]; // I think logically here could be useful for trimming the file. I mean just copy an specified part of the file.
while ((bufferSize = inputStream.read(bufffer)) > 0) {
outputStream.write(bufffer, 0, bufferSize);
}
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
This is a suggestion about how to copy your files, which it will copy them in internal storage under your application package name. Moreover, I have not tested the trim part yet. So, I am not sure about that.
One more thing, you can get the path directory of your application by
getFilesDir();
Our current project requires us to send an audio file to the server and then use the audio file for further computation.
Using the Java sound api, I was able to capture the recording and save it as a wav file in my system. Then in order to pass the audio wav to the server, I am using Apache Commons HttpClient to post a request to the server. (I am using InputstreamEntity provided by apache and sending the data as a chunk).
The problem appears when i am trying to recreate/retrieve the wav file on the server. I understand that I would have to use the AudioSystem.write API to create the wav file (exactly as what was done on my system). However what I observe is that althought the file gets created , it does not play (I am using vlc media player to test it FYI). I have searched in Google for sample codes and have tried to implement it, but is unable to play it once the file gets created.
The sample code snippets indicates the approaches i have tried:
//******************************************************************
try {
InputStream is = request.getInputStream();
FileOutputStream fs = new FileOutputStream("output123.wav");
byte[] tempbuffer = new byte[4096];
int bytesRead;
while((bytesRead=is.read(tempbuffer))!=-1)
{
fs.write(tempbuffer, 0,bytesRead);
}
is.close();
fs.close();
AudioInputStream inputStream =AudioSystem.getAudioInputStream(newFile("output123.wav"));
int numofbytes = inputStream.available();
byte[] buffer = new byte[numofbytes];
inputStream.read(buffer);
int bytesWritten = AudioSystem.write(inputStream, AudioFileFormat.Type.WAVE,new File("outputtest.wav"));
System.out.println("written"+bytesWritten);
Approach 2
InputStream is = request.getInputStream();
System.out.println("inputStream obtained : "+is.toString());
ByteArrayInputStream bais = null;
byte[] audioBuffer = IOUtils.toByteArray(is);
System.out.println(" is audioBuffer empty? : length = ? "+audioBuffer.length);
try {
AudioFileFormat ai = AudioSystem.getAudioFileFormat(is);
System.out.println("ai bytelength ? "+ai.getByteLength());
System.out.println("ai frame length = "+ai.getFrameLength());
Set<Map.Entry<String,Object>> audioProperties = ai.getFormat().properties().entrySet();
System.out.println("entry set is empty ? "+audioProperties.isEmpty());
for(Map.Entry me : audioProperties){
System.out.println("key = "+me.getKey());
System.out.println("value ="+me.getValue());}
bais = new ByteArrayInputStream(audioBuffer);
AudioInputStream ais = new AudioInputStream(bais, new AudioFormat(8000,8,2,true,true), 2);
AudioSystem.write(ais, AudioFileFormat.Type.WAVE,new File("testtest.wav"));
//*************************************************************************************
The audioFormat properties all turned out to be null. Are these null values giving the problem? So while creating the wave file on the server, I tried to set the properties manually once again. But even then the wav file would not play.
I have also tried quite a few approaches already mentioned on this site, but somehow they aren't working. I am sure i am missing something, but I am unable to pinpoint the exact problem.
Would be really helpful, if you guys can point out how to go about the conversion from ServletInputStream to getting a wav.
P.S (1) I know the code is shabby, because i have been under a trial and error situation for quite some time now. But I will give more details on the approaches if needed.
2) Apologise for the clumsiness, this happens to be my first post.. )
this is not how you copy a stream (from Approach 1). you have the correct code to copy a stream just above this.:
int numofbytes = inputStream.available();
byte[] buffer = new byte[numofbytes];
inputStream.read(buffer);
If all your server wants to do is get the data and write it to a file, then you do not need to use any of the audio API: simply treat the data as a stream of bytes.
So the part of approach 1 that is before any mention of AudioInputStream should be sufficient.
Although the approach chosen might not be the perfect solution, due to time constraints, I adopted a simpler approach. Using java.util.zip i simply zipped it up and sent it over to the server and then wrote a layer wherin the file gets unzipped . then i deleted the zip files. Seems like an immature solution (bcos the original challenge was to send the audio file). now i am incurring an overhead of zipping the files, but the file transfer would hapeen relatively faster. Thanks for your help guys.