Apache FTPClient - java

I'm writing a very simple FTPClient application using Apache's library.
All I do is download a jar file from a server. There is no exception, the application works fine when I run in on MacOS and as soon as I run the same code in Windows the downloaded file is smaller than the file on server. However, there is no exception and everything seems to be fine.
I'm going crazy, I'm using binary mode and the code is so simple I can't believe I've been stuck on it since yesterday!!!
Please help!
public boolean loadLatest(){
FTPClient ftp = new FTPClient();
try {
ftp.connect("server address");
ftp.setControlKeepAliveTimeout(300);
ftp.enterLocalPassiveMode();
String fu = "username";
ftp.login(fu, "password");
int reply = ftp.getReplyCode();
if (FTPReply.isPositiveCompletion(reply)) {
ftp.setFileTransferMode(FTP.BINARY_FILE_TYPE);
ftp.enterLocalPassiveMode();
FTPFilter filter = new FTPFilter();
FTPFile[] finfo = ftp.listFiles(".",filter);
if (finfo.length==0){
return false;
}
File currentJar = new File("sm.jar");
FileOutputStream output;
output = new FileOutputStream("sm.jar");
if (ftp.retrieveFile(finfo[0].getName(), output)==false){
System.out.println("Bad file!");
}
output.close();
ftp.logout();
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
Here is my code:
Thanks

You may have misused the Apache API.
public boolean setFileTransferMode(int mode) throws IOException
Sets the transfer mode. The default transfer mode FTP.STREAM_TRANSFER_MODE if this method is never called or if a connect method is called.
The possible values are STREAM_TRANSFER_MODE, STREAM_TRANSFER_MODE, or BLOCK_TRANSFER_MODE.
So your following line :
ftp.setFileTransferMode(FTP.BINARY_FILE_TYPE);
Is not valid use of the API, and does not setup the client to work in BINARY mode.
The FTP transfert mode as you call it, is actually controled by another method :
public boolean setFileType(int fileType) throws IOException
Sets the file type to be transferred. This should be one of FTP.ASCII_FILE_TYPE , FTP.BINARY_FILE_TYPE, etc. The file type only needs to be set when you want to change the type. After changing it, the new type stays in effect until you change it again. The default file type is FTP.ASCII_FILE_TYPE if this method is never called.
The server default is supposed to be ASCII (see RFC 959), however many ftp servers default to BINARY. To ensure correct operation with all servers, always specify the appropriate file type after connecting to the server.
N.B. currently calling any connect method will reset the type to FTP.ASCII_FILE_TYPE.
Most probably, you need to use this last method to change the mode to BINARY, and your transfer should be OK.

Related

Soap service can't write to XML file

Simple Soap service running on Axis engine on Tomcat v9.0 server needs to read and write to XML files. I developed soap service in Eclipse like a dynamic web project, so the XML files are in the WebContent->WEB-INF->resources->...
When i read the files everything works fine, but when i want to write to the files i get InvocationTargetException. Since i read files normaly, I guess that i'm not opening stream as i should when i write in the files, so can anyone guide me how to do this properly?
Here's the method for reading the file, and this WORKS:
public Station deserialization(String name, String path) {
Station s=null;
try {
URL url=getClass().getClassLoader().getResource(path+File.separator+name+".xml");
InputStream is=url.openStream();
XMLDecoder decoder = new XMLDecoder(is);
s=(Station) decoder.readObject();
decoder.close();
} catch (Exception e) {
Main.LOGGER.info("Station deserializaton was not successful!");
}
return s;
}
and here's the method for writing into the file, this DOESN'T work:
public boolean serialize(Station s, String path) {
try {
URL url=getClass().getClassLoader() .getResource(path+File.separator+s.getName()+".xml");
URLConnection con=url.openConnection();
con.setDoOutput(true);
OutputStream out=con.getOutputStream();
XMLEncoder encoder = new XMLEncoder(out);
encoder.writeObject(s);
encoder.close();
} catch (Exception e) {
Main.LOGGER.info("Station serialization was not successful!");
return false;
}
return true;
}
My real question here is how come the same principle work when reading the file and doesn't work with writing into the file? File paths are the same in both methods.
I found what was the problem. Turns out you can read files with URL, but you cant write to URL or URLConnection. I had to use FileOutputStream for writing into the files:
XMLEncoder encoder=new XMLEncoder(new FileOutputStream("file_path"));
You can also keep the files in WebContent->WEB-INF (if you develop web service in Eclipse) if you want web service to use them, becuse it then makes copies of them.
Just keep an eye on the path that you are providing, double check if it is the right one!

FileWriter to write to user desktop in Java, rather than server desktop

As part of a search application, I want the user to be able to download a report showing the results in a CSV file. I have the following method:
public void downloadCustomerResults(String customer) {
String output = "";
output += produceCustomerID(customer);
output += produceCustomerAddress(customer);
output += produceCustomerContactDetails(customer);
output += produceOrderHeader(customer);
output += producePayments(customer);
// Writes to server desktop, not user desktop.
try {
Writer fileWriter = new FileWriter("C:\\Users\\username\\Desktop\\SAR" + customer + "C.csv");
fileWriter.write(output);
fileWriter.flush();
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
This downloads the file to the desktop of the machine running the server, not the user's desktop (accessing the app via JSP's on Tomcat). How would I change the file path string to make this download to the users' desktop? Or would I have to pass the file to the JSP for the user to download via their browser?
Thanks.
Short answer: The server has no means of accessing the client's filesystem.
Longer answer: You might either provide a service for the client to download the file (e.g. a webservice accessible through a URI, like #Kayaman mentioned) or the client provides you a service to write the file (e.g. a remote file system, an FTP server etc.). For the latter there might be libraries providing a special java.nio.FileSystem extension.
You may also provide an application running on the client to receive the file. This client application will then have acces to the client's file systems (unless it lacks the access rights, of course).
So the answer I found was to use the JavaScript package FileSaver.js.
This accepts a blob created from a string, and then saves it with a filename of your choice to the browsers preferred download folder.
I managed to pass the string from Java to JavaScript, and then pass it through FileSaver.js in the .JSP page.

How to check that file is opened by another process in Java? [duplicate]

I need to write a custom batch File renamer. I've got the bulk of it done except I can't figure out how to check if a file is already open. I'm just using the java.io.File package and there is a canWrite() method but that doesn't seem to test if the file is in use by another program. Any ideas on how I can make this work?
Using the Apache Commons IO library...
boolean isFileUnlocked = false;
try {
org.apache.commons.io.FileUtils.touch(yourFile);
isFileUnlocked = true;
} catch (IOException e) {
isFileUnlocked = false;
}
if(isFileUnlocked){
// Do stuff you need to do with a file that is NOT locked.
} else {
// Do stuff you need to do with a file that IS locked
}
(The Q&A is about how to deal with Windows "open file" locks ... not how implement this kind of locking portably.)
This whole issue is fraught with portability issues and race conditions:
You could try to use FileLock, but it is not necessarily supported for your OS and/or filesystem.
It appears that on Windows you may be unable to use FileLock if another application has opened the file in a particular way.
Even if you did manage to use FileLock or something else, you've still got the problem that something may come in and open the file between you testing the file and doing the rename.
A simpler though non-portable solution is to just try the rename (or whatever it is you are trying to do) and diagnose the return value and / or any Java exceptions that arise due to opened files.
Notes:
If you use the Files API instead of the File API you will get more information in the event of a failure.
On systems (e.g. Linux) where you are allowed to rename a locked or open file, you won't get any failure result or exceptions. The operation will just succeed. However, on such systems you generally don't need to worry if a file is already open, since the OS doesn't lock files on open.
// TO CHECK WHETHER A FILE IS OPENED
// OR NOT (not for .txt files)
// the file we want to check
String fileName = "C:\\Text.xlsx";
File file = new File(fileName);
// try to rename the file with the same name
File sameFileName = new File(fileName);
if(file.renameTo(sameFileName)){
// if the file is renamed
System.out.println("file is closed");
}else{
// if the file didnt accept the renaming operation
System.out.println("file is opened");
}
On Windows I found the answer https://stackoverflow.com/a/13706972/3014879 using
fileIsLocked = !file.renameTo(file)
most useful, as it avoids false positives when processing write protected (or readonly) files.
org.apache.commons.io.FileUtils.touch(yourFile) doesn't check if your file is open or not. Instead, it changes the timestamp of the file to the current time.
I used IOException and it works just fine:
try
{
String filePath = "C:\sheet.xlsx";
FileWriter fw = new FileWriter(filePath );
}
catch (IOException e)
{
System.out.println("File is open");
}
I don't think you'll ever get a definitive solution for this, the operating system isn't necessarily going to tell you if the file is open or not.
You might get some mileage out of java.nio.channels.FileLock, although the javadoc is loaded with caveats.
Hi I really hope this helps.
I tried all the options before and none really work on Windows. The only think that helped me accomplish this was trying to move the file. Event to the same place under an ATOMIC_MOVE. If the file is being written by another program or Java thread, this definitely will produce an Exception.
try{
Files.move(Paths.get(currentFile.getPath()),
Paths.get(currentFile.getPath()), StandardCopyOption.ATOMIC_MOVE);
// DO YOUR STUFF HERE SINCE IT IS NOT BEING WRITTEN BY ANOTHER PROGRAM
} catch (Exception e){
// DO NOT WRITE THEN SINCE THE FILE IS BEING WRITTEN BY ANOTHER PROGRAM
}
If file is in use FileOutputStream fileOutputStream = new FileOutputStream(file); returns java.io.FileNotFoundException with 'The process cannot access the file because it is being used by another process' in the exception message.

create client side file using java

i am trying to create a project which create a file in client side . i ave done the coding to create a file .but it obviously will be created in server side.. can any one help to do this. below is the code i have done..
File file = new File("d:/file.txt");
try {
String content = "This is the content to write into file";
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
}
I have also tried to create a file using filesysapi, which is done using HTML and javascript. but i got "Error: SECURITY_ERR"
Despite what everyone is saying, you can create a client-side file via javascript. It's a sandboxed portion of the File System, done via HTML5's FileSystem API.
HOWEVER, my guess is your SECURITY_ERR is probably because you are opening an html page with the target javascript via File://PATH_TO_HTML_PAGE in your browser. The File-System API Will not work unless your grabbing the html/javascript/css from a server (like locahost:8080/test.html - Netbeans has some options to run a glassfish/server instance pretty painlessly locally on your machine if you have no experience with servers.).
Update 1-31-2014
Found this in an article on the File-System API, which confirmed the above paragraph for me:
You may need the --allow-file-access-from-files flag if you're debugging your app from file://. Not using these flags will result in a SECURITY_ERR or QUOTA_EXCEEDED_ERR FileError.
end update
That said, in the previous comment on a different question you asked and I answered, you were using TEMPORARY Storage. I use PERSISTENT because it is more reliable, and the browser displays a message asking for permission to store the data locally on the target machine. Here is how I have been making files locally on client machines for persistent data storage for the past couple years. This to the best of my knowledge only works with a handful of browser's, I use Google Chrome - the following defeinitely works in Google Chrome.
The following is javascript and needs to be within either an external script or script tags.
//this is a callback function that gets passed to your request for the file-System.
var onInitFs = function(fileSys){
//fileSystem is a global variable
fileSystem = fileSys;
//once you have access to the fileSystem api, then you can create a file locally
makeAFile();
makeAndWriteContent();
};
var errorHandler = function(e){console.log('Error', e);};
//request 1 GB memory in a quota request
//note the internal callback `function(grantedBytes){...}` which makes the actual
//request for the Filesystem, on success `onInitFs` is called.
///on error the `errorHandler` is called
navigator.webkitPersistentStorage.requestQuota(1024*1024*1024*1, function(grantedBytes) {
window.webkitRequestFileSystem(PERSISTENT, grantedBytes, onInitFs, errorHandler);
}, errorHandler);
//this method will only work once the fileSystem variable has been initialized
function makeAFile(){
var callbackFunctionOnSuccess = function(){console.log("created new file")}
fileSystem.root.getFile("test.txt", {
create: true
}, callbackFunctionOnSuccess, function(error){console.log(error);});
}
function makeAndWriteContent(){
//this is going to be passed as a callback function, to be executed after
//contents are written to the test2.txt file.
var readFile = function(){
fileSystem.root.getFile("test2.txt", {create: false}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
console.log(this.result);
};
reader.readAsText(file);
}, function(error){console.log(error);});
}, function(error){console.log(error);});
}
fileSystem.root.getFile("test2.txt", {
create: true
}, function(fileEntry) {
fileEntry.createWriter(function(writer) {
writer.onwriteend = function(e) {
writer.onwriteend = function(e){
//now, we will read back what we wrote.
readFile();
}
writer.onerror = function(e3){console.log(e3);
}
var blob = new Blob(["Hello World"]);
writer.write(blob);
};
writer.onerror = function(e3) {console.log(e3);};
//make sure our target file is empty before writing to it.
writer.truncate(0);
}, errorHandler);
}, errorHandler);
}
One thing to keep in mind is that the File-System API is asynchronous so you have to get use to using callback functions. If you try to access the File-System API before it's instantiated, or if you try to access files before they are ready, you will also get errors. Callback functions are essential.
using socket programming, 1st create a communication between server and client machines.
Socket kkSocket = new Socket(hostName, portNumber)
then use File file = new File("hostname#d:/file.txt");
if your host file does not contain hostname IP address maping, then instead of giving hostname, use IP address.
You can not create file on client side because browser does not allow doing that.

FTPing a file to Mainframe using Java, Apache Common Net

I'm am trying to upload a file into mainframe server using FTP. My code is below
FTPClient client = new FTPClient();
InputStream in = null;
FileInputStream fis = null;
try {
client.connect("10.10.23.23");
client.login("user1", "pass123");
client.setFileType(FTPClient.BINARY_FILE_TYPE);
int reply ;
reply = client.getReplyCode();
System.out.println("Reply Code:"+reply);
if(FTPReply.isPositiveCompletion(reply)){
System.out.println("Positive reply");
String filename ="D:\\FILE.txt";
in = new FileInputStream(filename);
client.storeFile("FILE.TXT", in);
client.logout();
fis.close();
} else {
System.out.println("Negative reply");
}
} catch(final Throwable t){
t.printStackTrace();
}
The code gets struck in client.storeFile("FILE.TXT", in);
I am unable to debug. Please suggest ways / solutions.
First there is what Lukas said fis is null, but I have a bunch of other questions. What is FTPClient? It is not sun.net.ftp.FtpClient as that class has no store() method. Other things to consider is logging into the mainframe, where I work you can't just grab files off the mainframe without first logging in. There can be more things to consider but lets start there.
You don't appear to be changing to a specific directory before uploading the file. There are two ways of changing directories on the Mainframe. If you need to upload to a PDS you would execute a command like the following from with in the windows ftp client.
cd USERID.DATASET.PREFIX
If you need to upload a file to the USS subsystem you would execute a command like the following.
cd '/direone/dirtwo'
Have you checked that user1 has access permissions to ftp? It is possible to grant those on a very granular level so that you can list files and submit jobs, but not put files.
The fact that it dies right after your SEND seems like that might be a good candidate. I would call your RACF / ACF2 / Whatever-security-product person you have and ask them.
first remove the file extension from the file name
enclose the resultant file name after trimming within single quotes
now put the above string as the first parameter of storeFile() method

Categories