I would like to ask if there is a way how to check if file already exists in the folder using only Apache Commons.
I have method which uploads into the SFTP folder but it overwrites current files anytime the method is running. The method is set to run every 5 minutes. I need a code which will create and if statement which checks if the file is not at the SFTP location already and then, if not executes my copy method, if there is a file, then skips it.
My copy method looks like this
private void copyFileSFTP(File model, String hour) throws IOException {
StandardFileSystemManager manager = new StandardFileSystemManager();
String dest = String.format("%s/%s/model/%s", destinationPath, hour,
model.getName());
remoteDirectory = String.format("%s/%s/model/", destinationPath, hour);
try {
if (!model.exists())
LOG.error("Error. Local file not found");
// Initializes the file manager
manager.init();
// Setup our SFTP configuration
FileSystemOptions opts = new FileSystemOptions();
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
opts, "no");
SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts,
false);
SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);
// Create the SFTP URI using the host name, userid, password, remote
// path and file name
String sftpUri = "sftp://" + userId + ":" + password + "#"
+ serverAddress + "/" + remoteDirectory + model.getName();
**HERE I NEED THE CHECK IF THE MODEL EXISTS ALREADY ON SFTP**
// Create local file object
FileObject localFile = manager.resolveFile(model.getAbsolutePath());
// Create remote file object
FileObject remoteFile = manager.resolveFile(sftpUri, opts);
// Copy local file to sftp server
remoteFile.copyFrom(localFile, Selectors.SELECT_SELF);
LOG.info("File upload successful");
LOG.info("New file has been created.");
LOG.info(dest);
} catch (Exception ex) {
LOG.error(ex);
handleBadPath(model, hour);
} finally {
manager.close();
}
}
Thank you for help.
Use FileObject.exists() method.
See https://commons.apache.org/proper/commons-vfs/commons-vfs2/apidocs/org/apache/commons/vfs2/FileObject.html#exists--
Related
I'm trying to make an Azure Function in Java. I need to make an excel file and upload it in BLOB container.
When I build the project and the tests start, then it works without problems and it uploads the file in the container, when instead I debug the project or I deploy it on Azure and I run it via internet (calling the service), it doesn't upload it. It blocks when it tries to upload the file.
Can you help me please? I'm on this problem since a few days.
Thank you.
I attach the method where it uploads the file:
#FunctionName("FunctionTest")
public HttpResponseMessage run(
#HttpTrigger(
name = "req",
methods = {HttpMethod.GET, HttpMethod.POST},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
final String queryAccountName = request.getQueryParameters().get("AccountName");
String accountName = request.getBody().orElse(queryAccountName);
final String queryAccountKey = request.getQueryParameters().get("AccountKey");
String accountKey = request.getBody().orElse(queryAccountKey);
context.getLogger().info("Azure Blob storage v12 - Java quickstart sample\n");
// Retrieve the connection string for use with the application. The storage
// connection string is stored in an environment variable on the machine
// running the application called AZURE_STORAGE_CONNECTION_STRING. If the environment variable
// is created after the application is launched in a console or with
// Visual Studio, the shell or application needs to be closed and reloaded
// to take the environment variable into account.
// String connectStr = System.getenv("AZURE_STORAGE_CONNECTION_STRING");
//String connectStr = "DefaultEndpointsProtocol=https;AccountName="+accountName+";AccountKey="+accountKey+";EndpointSuffix=core.windows.net";
// Create a BlobServiceClient object which will be used to create a container client
//BlobServiceClient blobServiceClient = new BlobServiceClientBuilder().connectionString(connectStr).buildClient();
StorageSharedKeyCredential credential = new StorageSharedKeyCredential(accountName, accountKey);
String endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName);
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder().endpoint(endpoint).credential(credential).buildClient();
//Create a unique name for the container
String containerName = "container-name";
// Create the container and return a container client object
//BlobContainerClient containerClient = blobServiceClient.createBlobContainer(containerName);
BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(containerName);
// Create a local file in the ./data/ directory for uploading and downloading
/*String pathFile = "./data/";
String fileName = "quickstart" + java.util.UUID.randomUUID() + ".txt";
File localFile = new File(pathFile + fileName);
// Write text to the file
FileWriter writer;
try {
writer = new FileWriter(pathFile + fileName, true);
writer.write("Hello, World!");
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
// Get a reference to a blob
// Upload the blob
String pathFile = System.getenv("TEMP") + "\\";
String fileName = creaReport(context)+".xlsx"; // creating file Excel - IT DOESN'T EVEN WORK WITH TXT FILE
BlobClient blobClient = containerClient.getBlobClient(fileName);
System.out.println("\nUploading to Blob storage as blob:\n\t" + blobClient.getBlobUrl());
blobClient.uploadFromFile(pathFile + fileName, true); // IT BLOCKS HERE
System.out.println("\nListing blobs...");
// List the blob(s) in the container.
for (BlobItem blobItem : containerClient.listBlobs()) {
System.out.println("\t" + blobItem.getName());
}
// Download the blob to a local file
// Append the string "DOWNLOAD" before the .txt extension so that you can see both files.
//String downloadFileName = fileName.replace(".txt", "DOWNLOAD.txt");
String downloadFileName = fileName.replace(".xlsx", "DOWNLOAD.xlsx");
File downloadedFile = new File(pathFile + downloadFileName);
System.out.println("\nDownloading blob to\n\t " + pathFile + downloadFileName);
blobClient.downloadToFile(pathFile + downloadFileName, true);
// Clean up
System.out.println("\nPress the Enter key to begin clean up");
System.console().readLine();
/*System.out.println("Deleting blob container...");
containerClient.delete();*/
System.out.println("Deleting the local source and downloaded files...");
localFile.delete();
downloadedFile.delete();
System.out.println("Done");
return request.createResponseBuilder(HttpStatus.OK).body("Blob uploaded").build();
}
For this problem, I test it in my side and summarize the point as below:
The reason for this problem is the files in local/temp are not shared among site instances. You can refer to this page.
So I met the same problem as you, I deploy my java function to azure and add a file under local/temp path manually. Then run the function, it can't access the data of the file.
After that, I edit my function code. Create a txt file by the code below in my function:
String filePath="d:\\local\\Temp\\test1.txt";
File file = new File(filePath);
try {
FileWriter writer = new FileWriter(file);
writer.write("Test data");
writer.close();
} catch (IOException e1) {
context.getLogger().info(e1.getMessage());
e1.printStackTrace();
}
And then read the file in the same function by the code below:
InputStream is = null;
int i;
char c;
try {
is = new FileInputStream(filePath);
while ((i = is.read()) != -1) {
c = (char) i;
context.getLogger().info("===inputstream==" + c);
}
} catch (Exception e) {
context.getLogger().info("===try catch error");
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
context.getLogger().info("===finally error");
e.printStackTrace();
}
}
}
Deploy the code to azure, the function app run in a consumption plan(so it will just use one instance if I just run it once). Running it, I read the data of the file success.
According to the test above, I suggest you do not create the file in local/temp. You'd better create the file in d:\home\site\wwwroot, you can create a folder under wwwroot and create the files in the folder. I test it works fine.
Hope it helps~
Spring boot application. User selects server of their choice and a file on their local system and the file gets SFTP to that server.
This works by: input stream reading the file into a folder within the root project. The sftp method needs the file path to work. Since I'm unable to get the file path of the file on the users system and just get the file, I bring it locally and then supply the path from there.
This work perfectly when running my project from intellij and NOT so perfectly when packaged as a jar.
After some reading, it looks like it's not great to bring in a file into a jar. Any ideas on a route to take now? Thanks
public void SFTP(MultipartFile file, String friendlyName, String filePath) throws Exception {
String host = "10.3.152.245"; //host:IP
String user = "cloud";
String password = "Password1";
System.out.println("File path: " + filePath);
try {
String fileName = renameLocal(file);
java.util.Properties config = new java.util.Properties();
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, 22);
session.setPassword(password);
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp");
sftpChannel.connect();
sftpChannel.cd("/");
sftpChannel.cd(filePath);
sftpChannel.put("\\upload-dir\\" + fileName, ".");
sftpChannel.rename(filePath + "/" + fileName, filePath + "/" + file.getOriginalFilename());
session.disconnect();
sftpChannel.disconnect();
Path path = FileSystems.getDefault().getPath(".\\upload-dir\\" + fileName);
Files.delete(path);
}catch (Exception e){
throw new Exception();
}
}
the method above is the SFTP method that's called when a user uploads a file. Static host user and pass for now. As you see, I'm putting the file locally (method not here) in the upload-dir. Then providing upload-dir\filename to the sftpChannel.put method
I'm attempting to use Apache Commons VFS to SFTP a file onto a server, but I keep getting the following error:
java.lang.RuntimeException: org.apache.commons.vfs2.FileSystemException: Could not connect to SFTP server at "sftp://user:***#xxx.x.xxx.xxx/".
Is it normal for it to not include the remote file path (remoteFilePath) here? It's in my code to include it in the connection string (see below)
I have the following jars included in my pom:
commons-logging-1.1.3.jar
commons-vfs2-2.0.jar
hamcrest-core-1.3.jar
jsch-0.1.50.jar
Code:
public void SftpMethod(String strMsg, String tableName){
String host = "xxx.x.xxx.xxx";
String user = "user";
String pass = "password!";
String localFilePath = "C:\\Users\\exampleDir\\Desktop\\loc.dat";
String remoteFilePath = "/dir/home/user/export/loc.dat";
StandardFileSystemManager manager = new StandardFileSystemManager();
File file = new File(localFilePath);
if (!file.exists())
throw new RuntimeException("Error. Local file not found");
try{
manager.init();
// Create local file object
FileObject localFile = manager.resolveFile(file.getAbsolutePath());
// Create remote file object
FileObject remoteFile = manager.resolveFile(
createConnectionString(host, user, pass, remoteFilePath),
createDefaultOptions());
// Copy local file to SFTP server
remoteFile.copyFrom(localFile, Selectors.SELECT_SELF);
System.out.println("File upload success");
}catch(IOException e){
throw new RuntimeException(e);
}finally{
manager.close();
}
}
public static String createConnectionString(String hostName, String username, String password, String remoteFilePath) {
return "sftp://" + username + ":" + password + "#" + hostName + "/" + remoteFilePath;
}
public static FileSystemOptions createDefaultOptions() throws FileSystemException {
// Create SFTP options
FileSystemOptions opts = new FileSystemOptions();
// SSH Key checking
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(opts, "no");
/*
* Using the following line will cause VFS to choose File System's Root
* as VFS's root. If I wanted to use User's home as VFS's root then set
* 2nd method parameter to "true"
*/
// Root directory set to user home
SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
// Timeout is count by Milliseconds
SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);
return opts;
}
Without the full stack trace its hard to give a conclusive answer, but this is what I saw recently:
Caused by: org.apache.commons.vfs2.FileSystemException: Could not load private key from "/Users/<user>/.ssh/id_rsa".
at org.apache.commons.vfs2.provider.sftp.SftpClientFactory.createConnection(SftpClientFactory.java:131)
Unfortunately, I wasn't trying to use a public/private key. I was only intending to log in with a username/password. I needed a way for it to stop trying to read my private key.
The root cause was that the code was using a default location for my key, and attempting to read it (even though thats not what I wanted).
So the workaround was to override the default location by setting the following property:
System.setProperty("vfs.sftp.sshdir", "/");
This bypassed the attempt to read the ssh key altogether, and successfully connected.
I set-up a server with FreeSSHd and am able to Putty it, including changing directories and listing files. I have some example .txt files and a folder in the home directory. I set the home directory on my server to "C:\SFTP" using FreeSSHd (as opposed to defining a HOME variable with the directory being "$HOME\").
Apparently, when using JSch,
JSch jsch = new JSch();
session = jsch.getSession(username,host,port);
jsch.addIdentity(key.getAbsolutePath());
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setUserInfo(new MyUserInfo());
session.connect();
channel = session.openChannel("sftp");
channel.connect();
channelSftp = (ChannelSftp)channel;
System.out.println("Home: "+channelSftp.getHome());
the last line prints just "Home: /". Any attempts (made immediately after above code) to use
channelSftp.cd(WORKINGDIR);
results in
2: No such file
at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2833)
at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2185)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:1295)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:1267)
at test.SFTPTest.main(SFTPTest.java:71)
I think if I got to the root of why JSch does not have the correct home path (or any?) this would work. Also, strangely enough I upload and download files no problem using put() and get().
I've heard all kinds of things where people look into the source and find it does strange things in resolving paths and something with a method called "_realPath()" and superfluous leading/trailing "/" but I don't even have it telling me the home directory is correct after connecting.
Any ideas?
ThankĀ“s everybody for your comments.
OS windows XP,I installed FreeSSHd and setting the default directory, then, when I tryng connect by console ssh, the directory was "/", I writing chdir but directory was: C:\Windows\system32\ this is very confused...
My Java code:
public void recursiveFolderUpload(String sourcePath, String destinationPath) throws FileNotFoundException {
if (c == null || session == null || !session.isConnected() || !c.isConnected()) {
log.debug("Connection to server is closed. Open it first.");
}
try {
// c.put(sourceFile, destinationFile);
// log.info("Upload successfull.");
File sourceFile = new File(sourcePath);
if (sourceFile.isFile()) {
// copy if it is a file
c.cd(destinationPath);
if (!sourceFile.getName().endsWith("."))
c.put(new FileInputStream(sourceFile), sourceFile.getName(), c.OVERWRITE);
} else {
log.info("Inside else " + sourceFile.getName());
File[] files = sourceFile.listFiles();
if (files != null && !sourceFile.getName().startsWith(".")) {
log.info("Directory remote server: " + c.pwd());
c.cd(destinationPath);
SftpATTRS attrs = null;
// check if the directory is already existing
try {
attrs = c.stat(destinationPath + sourceFile.getName());
} catch (Exception e) {
log.warn(destinationPath + sourceFile.getName() + " not found");
//e.printStackTrace();
}
// else create a directory
if (attrs != null) {
log.info("Directory exists IsDir : " + attrs.isDir());
} else {
log.info("Creating dir /" + sourceFile.getName());
c.mkdir(sourceFile.getName());
}
for (File f : files) {
if(!f.getName().contains(".dtd")){
log.info("Uploading file: " + f.getAbsoluteFile());
recursiveFolderUpload(f.getAbsolutePath(), destinationPath + sourceFile.getName() + "/");
}
}
}
}
} catch (SftpException e) {
e.printStackTrace();
}
}
My solution was only put the "/" en the input parameter destinationPath of method called recursiveFolderUpload
In other words, my properties file than so:
properties.host = IP
properties.user = user
properties.pass = pass
properties.port = port
properties.dir = / ---> This points to the directory configured by default in opensshd within windows
Thank so much everthing again.
SFTP directory should be the directory of the current user is not necessarily SFTP services with the directory, I also encountered the same problem, because I am with the directory and the user's default directory settings.
I tried to set the lastmodifeddate of local folder file as the lastmodifieddate of FTP file.
But, in the return value it returns false and date is also not set properly.
Here is the function,
public static void getModifiedDateAndTimeFromFTPFile(String FTPHost, String FTPUserName, String FTPPassword, String FTPRemoteDirectory, String localFilePath, String fileName) {
try{
//get Local File
File fileLocal = new File(localFilePath + fileName);
//Connect to FTP and get the lastmodified time of File.
FTPClient client = new FTPClient();
client.connect(FTPHost);
client.login(FTPUserName, FTPPassword);
client.changeWorkingDirectory(FTPRemoteDirectory);
FTPFile ftpFile = client.listFiles(fileName)[0];
//Get last_modified date of FTP file.
Date ftpFileDate = ftpFile.getTimestamp().getTime();
//Now set date to the Local File.
boolean boolSetTime = fileLocal.setLastModified(ftpFileDate.getTime());
System.out.println(" Was last modified time set successfully ? : " + boolSetTime);
} catch (Exception ex) {
System.out.println("Error : " + ex.toString());
}
}
Can anybody help me by pointing out my mistake?
Thanks
Most probably localFilePath + fileName do not form the intended filename. This won't give you a exception when constructing a File object, but setLastModified(...) would always return false on a non-existing file.
May be it's just a missing path separator?