Is it possible to do file/directory sync in Java using JSch ? I need to sync directory from a remote linux machine to my local windows machine. Is this possible ?
-Tivakar
The easiest way to download files from SCP server is using Commons VFS along with JSch:
import java.io.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.vfs2.*;
public class CopyRemoteFile {
public static void copyRemoteFiles(String host, String user, String remotePath, String localPath) throws IOException {
FileSystemOptions fsOptions = new FileSystemOptions();
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fsOptions, "no");
SftpFileSystemConfigBuilder.getInstance().setIdentities(fsOptions,
new File[] { new File(FileUtils.getUserDirectoryPath() + "/.ssh/id_dsa") });
DefaultFileSystemManager fsManager = (DefaultFileSystemManager) VFS.getManager();
String uri = "sftp://" + user + "#" + host + "/" + remotePath;
FileObject fo = fsManager.resolveFile(uri, fsOptions);
FileObject[] files = fo.getChildren();
for (FileObject file : files) {
// We will be dealing with the files here only
if (file.getType() == FileType.FILE) {
FileUtils.copyInputStreamToFile(file.getContent().getInputStream(),
new File(localPath + "/" + file.getName().getBaseName()));
}
file.close();
}
fo.close();
fsManager.close();
}
}
It's just an example I got in my Wiki, so nothing fancy. But do keep in mind that if you'll close fsManager, you will not be able to open it again in the same VM. I got this issue while testing this solution...
Although the example above does not import any JSch classes, you need to put it in the classpath anyway.
The above example is using private key to authenticate with the remote host. You can easily change that by providing password and modifying the uri to include that.
If you need to sync files, you can compare dates of the files on the local file system (or DB, or any other source of the information) and the remote files:
import java.io.*;
import org.apache.commons.io.*;
import org.apache.commons.vfs2.*;
import org.apache.commons.vfs2.impl.*;
import org.apache.commons.vfs2.provider.sftp.*;
public class CopyRemoteFile {
public static void copyRemoteFiles(final String host, final String user, final String remotePath, final String localPath)
throws IOException {
FileSystemOptions fsOptions = new FileSystemOptions();
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fsOptions, "no");
SftpFileSystemConfigBuilder.getInstance().setIdentities(fsOptions,
new File[] { new File(FileUtils.getUserDirectoryPath() + "/.ssh/id_dsa") });
DefaultFileSystemManager fsManager = (DefaultFileSystemManager) VFS.getManager();
String uri = "sftp://" + user + "#" + host + "/" + remotePath;
FileObject fo = fsManager.resolveFile(uri, fsOptions);
FileObject[] files = fo.getChildren();
for (FileObject file : files) {
// We will be dealing with the files here only
File newFile = new File(localPath + "/" + file.getName().getBaseName());
if (file.getType() == FileType.FILE && newFile.lastModified() != file.getContent().getLastModifiedTime()) {
FileUtils.copyInputStreamToFile(file.getContent().getInputStream(), newFile);
newFile.setLastModified(file.getContent().getLastModifiedTime());
}
file.close();
}
fo.close();
fsManager.close();
}
}
Look at: http://the-project.net16.net/Projekte/projekte/Projekte/Programmieren/sftp-synchronisierung.html
There is a whole Programm uploadet.
Here is the sync Part:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Vector;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.SftpException;
/*
* This is the heart of the whole Program. I hope, the descriptions are precise enought.
*/
public class Sync{
public String ServerPath;
public File LocalFolder;
public sFTPclient client;
public ArrayList<String> serverContentList;
public ArrayList<String> pathList;
public Sync(File local, String to, sFTPclient client){
this.LocalFolder = local;
this.ServerPath = to;
this.client = client;
}
/*
* Executed once. Sets the Server Directory if it exists.
* If the local folder doesn't exist on the Server, it creates it.
*/
public void setServerDirectory() throws SftpException{
try{
client.sftpChannel.cd(ServerPath);
}catch(Exception e){
GUI.addToConsole(ServerPath + " don't exist on your server!");
}
String serverFolder = ServerPath.substring(ServerPath.lastIndexOf('/')+1, ServerPath.length());
if(!LocalFolder.getName().equals(serverFolder)){
try{
client.sftpChannel.mkdir(LocalFolder.getName());
client.sftpChannel.cd(LocalFolder.getName());
} catch (Exception e){
client.sftpChannel.cd(LocalFolder.getName());
}
this.ServerPath = ServerPath + "/" + LocalFolder.getName();
GUI.setNewServerFolder(ServerPath);
}
serverContentList = new ArrayList<String>();
pathList = new ArrayList<String>();
}
//The contentlist contains all Filenames, that should be synchronized
public void setToContentList(String ServerFolder) throws SftpException{
#SuppressWarnings("unchecked")
Vector<LsEntry> fileList = client.sftpChannel.ls(ServerFolder);
int size = fileList.size();
for(int i = 0; i < size; i++){
if(!fileList.get(i).getFilename().startsWith(".")){
serverContentList.add(fileList.get(i).getFilename());
pathList.add(ServerFolder);
}
}
}
/*
* Deletes the synchronized elements from the Lists
*/
public void deleteFromLists(String name){
int position = serverContentList.lastIndexOf(name);
if(position >= 0){
serverContentList.remove(position);
pathList.remove(position);
}
}
/*
* Main function for synchronizing. Works recursive for local folders.
*/
#SuppressWarnings("unchecked")
public void synchronize(File localFolder, String ServerDir) throws SftpException, FileNotFoundException{
if(client.sftpChannel.pwd() != ServerDir){
client.sftpChannel.cd(ServerDir);
}
setToContentList(ServerDir);
File[] localList = localFolder.listFiles();
Vector<LsEntry> ServerList = client.sftpChannel.ls(ServerDir);
ServerList.remove(0); ServerList.remove(0);
/*
* Upload missing Files/Folders
*/
int size = localList.length;
for(int i = 0; i < size; i++){
if(localList[i].isDirectory()){
if(checkFolder(localList[i], ServerDir)){
synchronize(localList[i], ServerDir + "/" + localList[i].getName());
deleteFromLists("SubFolder");
}else {
newFileMaster(true, localList[i], ServerDir);
}
} else {
checkFile(localList[i], ServerDir);
}
deleteFromLists(localList[i].getName());
}
}
/*
* Deletes all files on the server, which are not in the local Folder. Deletes also all missing folders
*/
public void deleteRest() throws SftpException, FileNotFoundException{
int size = serverContentList.size();
for(int i = 0; i < size; i++){
client.sftpChannel.cd(pathList.get(i));
newFileMaster(false, null, serverContentList.get(i));
}
}
/*
* Copy or delete Files/Folders
*/
public void newFileMaster(boolean copyOrNot, File sourcePath, String destPath) throws FileNotFoundException, SftpException{
FileMaster copy = new FileMaster(copyOrNot, sourcePath, destPath, client.sftpChannel);
copy.runMaster();
}
/*
*Useful to find errors - Prints out the content-List every time you call the method.
*If you have Problems, call it before and after every changes of the serverContentList!
*/
/*public void printServerContent(){
System.out.println("SERVER-Content: " + "\n");
for(int i = 0; i < serverContentList.size(); i++){
System.out.println(serverContentList.get(i) + " in " + pathList.get(i));
}
}*/
/*
* Looks ond the server, if the file is there. If not, or the local file has changed, it copies the file on the server.
*/
public void checkFile(File file, String path) throws SftpException, FileNotFoundException{
client.sftpChannel.cd(path);
if(!serverContentList.contains(file.getName())){
newFileMaster(true, file, ServerPath);
} else {
Long localTimeStamp = file.lastModified();
Long timeStamp = client.sftpChannel.stat(file.getName()).getATime()*1000L;
if(localTimeStamp > timeStamp){
newFileMaster(false, null, path + "/" + file.getName());
newFileMaster(true, file, path);
}
}
deleteFromLists(file.getName());
}
/*
* The same as the checkFile function. But it returns a boolean. (Easier to handle in the synchronized funtion)
* Don't check, if the folder has changed (I think this can't be the case)
*/
public boolean checkFolder(File folder, String path) throws SftpException{
client.sftpChannel.cd(path);
if(serverContentList.contains(folder.getName())){
return true;
}else { return false; }
}
}
Related
I have a task to edit a file inside of a zip on SecureCRT.
I am able to run Linux commands remotely using JSCH library (com.jcraft.jsch)
Here is part of my code:
Session session = setUpSession(testParameters, softAsserter);
Channel channel = session.openChannel("exec");
((ChannelExec)channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream inputStream = channel.getInputStream();
channel.connect();
I wish to know what is the best way, or the right commands in order to edit a file (for example Test.txt) inside of a zip file on a SecureCRT server.
The contends inside the zip file can be modified in significant number of ways.
I have mentioned some ways which actually might work for you. In order to do that
We should securely transfer the source file/compiled file from local machine to server. The below link would help to transfer the file securely .
https://www.vandyke.com/int/drag_n_drop.html
As a first step , We should develop a snippet which is capable of modifying the contends of the zip file, Then we should copy the file to the server . Then we execute the command to run the file so that the contends inside the zip gets modified.
The below approach has been mentioned only to modify the zip contends.
Approach 1: Using a Simple Java snippet to achieve
We can write a simple java snippet which can open the zip file and edit , Keep the file in the machine and then execute the class file by just running "java filename" which would actually modify contends in the zip file.
Link which would help :
Modifying a text file in a ZIP archive in Java
import java.io.*;
import java.nio.file.*;
class RemoteEditFileContends {
/**
* Edits the text file in zip.
*
* #param zipFilePathInstance
* the zip file path instance
* #throws IOException
* Signals that an I/O exception has occurred.
*/
public static void editTextFileInZip(String zipFilePathInstance) throws IOException {
Path pathInstance = Paths.get(zipFilePathInstance);
try (FileSystem fileSystemIns = FileSystems.newFileSystem(pathInstance, null)) {
Path pathSourceInstance = fileSystemIns.getPath("/abc.txt");
Path tempCopyIns = generateTempFile(fileSystemIns);
Files.move(pathSourceInstance, tempCopyIns);
streamCopy(tempCopyIns, pathSourceInstance);
Files.delete(tempCopyIns);
}
}
/**
* Generate temp file.
*
* #param fileSystemIns
* the file system ins
* #return the path
* #throws IOException
* Signals that an I/O exception has occurred.
*/
public static Path generateTempFile(FileSystem fileSystemIns) throws IOException {
Path tempCopyIns = fileSystemIns.getPath("/___abc___.txt");
if (Files.exists(tempCopyIns)) {
throw new IOException("temp file exists, generate another name");
}
return tempCopyIns;
}
/**
* Stream copy.
*
* #param sourecInstance
* the src
* #param destinationInstance
* the dst
* #throws IOException
* Signals that an I/O exception has occurred.
*/
public static void streamCopy(Path sourecInstance, Path destinationInstance) throws IOException {
try (
BufferedReader bufferInstance = new BufferedReader(new InputStreamReader(Files.newInputStream(sourecInstance)));
BufferedWriter writerInstance = new BufferedWriter(
new OutputStreamWriter(Files.newOutputStream(destinationInstance)))) {
String currentLine = null;
while ((currentLine = bufferInstance.readLine()) != null) {
currentLine = currentLine.replace("key1=value1", "key1=value2");
writerInstance.write(currentLine);
writerInstance.newLine();
}
}
}
public static void main(String[] args) throws IOException {
editTextFileInZip("test.zip");
}
}
Approach 2: Using python to modify the zip files
How to update one file inside zip file using python
Approach 3 : Writing a shell script to modify the contends of zip file directly, So that we can copy the shell script to the server and then execute directly the shell script.
https://superuser.com/questions/647674/is-there-a-way-to-edit-files-inside-of-a-zip-file-without-explicitly-extracting
The below snippet would help you to connect and execute using the library.
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
public class ConnetionManager {
private static final Logger _logger = Logger.getLogger(ConnetionManager.class.getName());
private JSch jschSSHChannel;
private String strUserName;
private String strConnectionIP;
private int intConnectionPort;
private String strPassword;
private Session sesConnection;
private int intTimeOut;
private void doCommonConstructorActions(String userNameInstance, String tokenpassword, String connetionServerIo,
String hostFileName) {
jschSSHChannel = new JSch();
try {
jschSSHChannel.setKnownHosts(hostFileName);
} catch (JSchException exceptionInstance) {
_logError(exceptionInstance.getMessage());
}
strUserName = userNameInstance;
strPassword = tokenpassword;
strConnectionIP = connetionServerIo;
}
public ConnetionManager(String userName, String password, String connectionIP, String knownHostsFileName) {
doCommonConstructorActions(userName, password, connectionIP, knownHostsFileName);
intConnectionPort = 22;
intTimeOut = 60000;
}
public ConnetionManager(String userName, String password, String connectionIP, String knownHostsFileName,
int connectionPort) {
doCommonConstructorActions(userName, password, connectionIP, knownHostsFileName);
intConnectionPort = connectionPort;
intTimeOut = 60000;
}
public ConnetionManager(String userName, String password, String connectionIP, String knownHostsFileName,
int connectionPort, int timeOutMilliseconds) {
doCommonConstructorActions(userName, password, connectionIP, knownHostsFileName);
intConnectionPort = connectionPort;
intTimeOut = timeOutMilliseconds;
}
public String connect() {
String errorMessage = null;
try {
sesConnection = jschSSHChannel.getSession(strUserName, strConnectionIP, intConnectionPort);
sesConnection.setPassword(strPassword);
sesConnection.connect(intTimeOut);
} catch (JSchException exceptionInstance) {
errorMessage = exceptionInstance.getMessage();
}
return errorMessage;
}
private String _logError(String errorMessage) {
if (errorMessage != null) {
_logger.log(Level.SEVERE, "{0}:{1} - {2}", new Object[] { strConnectionIP, intConnectionPort, errorMessage });
}
return errorMessage;
}
private String _logWarnings(String warnMessage) {
if (warnMessage != null) {
_logger.log(Level.WARNING, "{0}:{1} - {2}", new Object[] { strConnectionIP, intConnectionPort, warnMessage });
}
return warnMessage;
}
public String sendCommand(String executionCommand) {
StringBuilder outputBuffer = new StringBuilder();
try {
Channel channelInstance = sesConnection.openChannel("exec");
((ChannelExec) channelInstance).setCommand(executionCommand);
InputStream commandOutputStream = channelInstance.getInputStream();
channelInstance.connect();
int readByte = commandOutputStream.read();
while (readByte != 0xffffffff) {
outputBuffer.append((char) readByte);
readByte = commandOutputStream.read();
}
channelInstance.disconnect();
} catch (IOException ioExceptionInstance) {
_logWarnings(ioExceptionInstance.getMessage());
return null;
} catch (JSchException schExceptionInstance) {
_logWarnings(schExceptionInstance.getMessage());
return null;
}
return outputBuffer.toString();
}
public void close() {
sesConnection.disconnect();
}
}
I use this function to detect if my file exists or not. While I have some image stored as .jpg, .JPG, .png, and .PNG. But it always return .jpg or .png as true even if the real file has extension .JPG or .PNG.
After I render it to my webpage it throws an error "Failed to load resource: the server responded with a status of 404 (Not Found)".
public static String getPhotoFileExtension(int empKey){
try{
String[] types = {".jpg",".JPG",".png", ".PNG"};
for(String t : types)
{
String path = "/"+Common.PHOTO_PATH + empKey + t;
File f = new File(Sessions.getCurrent().getWebApp()
.getRealPath(path));
if(f.isFile())
return t;
}
}catch (Exception e) {
e.printStackTrace();
}
return "";
}
So you want to get the real case sensitive names of files stored in your filesystem. Lets imaging we have the following paths:
on Linux: using ext4 (which is case sensitive) /testFolder/test.PnG
on Windows using NTFS (which is not case sensitive) c:\testFolder\test.PnG
Now lets create some Java File Objects to each Image File.
// on Linux
File f1 = new File("/testFolder/test.png");
File f2 = new File("/testFolder/test.PNG");
File f3 = new File("/testFolder/test.PnG");
f1.exists(); // false
f2.exists(); // false
f3.exists(); // true
// on Windows
File f1 = new File("c:\\testFolder\\test.png");
File f2 = new File("c:\\testFolder\\test.PNG");
File f3 = new File("c:\\testFolder\\test.PnG");
f1.exists(); // true
f2.exists(); // true
f3.exists(); // true
Your problem is that all calls of File like File.exists are redirected to the java.io.FileSystem class that represents real Operating System calls of your File System by the JVM. So you cannot distinguish on Windows Machines between test.PNG and test.png. Neither do Windows itself.
But even on Windows each File has a defined name in the File System that could be for example: test.PnG. You will see this in your Windows Explorer or in Command Line if you type dir c:\testFolder.
So what you can do in Java is use the File.list method on the parent directory that results in the Operating System list call for all files in this directory with their real names.
File dir = new File("c://testFolder//");
for(String fileName : dir.list())
System.out.println(fileName);
// OUTPUT: test.PnG
or if you prefer File Objects
File dir = new File("c://testFolder//");
for(File file : dir.listFiles())
System.out.println(file.getName());
// OUTPUT: test.PnG
You can use this to write your own exists Method that is case sensitive on all operating systems
public boolean exists(File dir, String filename){
String[] files = dir.list();
for(String file : files)
if(file.equals(filename))
return true;
return false;
}
Use it like this:
File dir = new File("c:\\testFolder\\");
exists(dir, "test.png"); // false
exists(dir, "test.PNG"); // false
exists(dir, "test.PnG"); // true
EDIT: I have to admit that I was wrong. There is a way to get the real name of a File. I always overlooked the method File.getCanonicalPath.
Again our example: We have that File c:\testFolder\test.PnG.
File f = new File("c://testFolder//test.png");
System.out.println(f.getCanonicalPath());
// OUTPUT: C:\testFolder\test.PnG
With that knowledge you can write a simple test method for the case sensitive extension without iterating all files.
public boolean checkExtensionCaseSensitive(File _file, String _extension) throws IOException{
String canonicalPath = _file.getCanonicalPath();
String extension = "";
int i = canonicalPath.lastIndexOf('.');
if (i > 0) {
extension = canonicalPath.substring(i+1);
if(extension.equals(_extension))
return true;
}
return false;
}
Use it like this:
File f = new File("c://testFolder//test.png");
checkExtensionCaseSensitive(f, "png"); // false
checkExtensionCaseSensitive(f, "PNG"); // false
checkExtensionCaseSensitive(f, "PnG"); // true
If you are looking for a function that in any platform can determine existence of a file and is case-sensitive; this should do it :
public static boolean fileExistsCaseSensitive(String path) {
try {
File file = new File(path);
return file.exists() && file.getCanonicalFile().getName().equals(file.getName());
} catch (IOException e) {
return false;
}
}
I started messing around a little with this because I haven't used Apache's IOFileFilter before and thought that I would add this solution as a chance to play with it a little.
Here is the code:
import java.io.File;
import java.util.Collection;
import java.util.Optional;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
public class CaseInsensitiveFileFinder {
/**
* Attempts to find a file with the given <code>fileName</code> (irrespective of case) in the given
* <code>absoluteDirPath</code>. Note that while this method is able to find <code>fileName</code> ignoring case, it
* may not be able to do so if <code>absoluteDirPath</code> is in an incorrect case - that behavior is OS dependent.
*
* #param absoluteDirPath the absolute path of the parent directory of <code>fileName</code> (e.g. "/Users/me/foo")
* #param fileName the name of the file including extension that may or may not be the correct case
* (e.g. myfile.txt)
* #return an optional reference to the file if found, {#link Optional#empty()} will be returned if the file is not
* found
*/
public Optional<File> findFileIgnoreCase(String absoluteDirPath, final String fileName) {
File directory = new File(absoluteDirPath);
if (!directory.isDirectory()) {
throw new IllegalArgumentException("Directory '" + absoluteDirPath + "' isn't a directory.");
}
IOFileFilter caseInsensitiveFileNameFilter = new IOFileFilter() {
#Override
public boolean accept(File dir, String name) {
boolean isSameFile = fileName.equalsIgnoreCase(name);
return isSameFile;
}
#Override
public boolean accept(File file) {
String name = file.getName();
boolean isSameFile = fileName.equalsIgnoreCase(name);
return isSameFile;
}
};
Collection<File> foundFiles = FileUtils.listFiles(directory, caseInsensitiveFileNameFilter, null);
if (foundFiles == null || foundFiles.isEmpty()) {
return Optional.empty();
}
if (foundFiles.size() > 1) {
throw new IllegalStateException(
"More requirements needed to determine what to do with more than one file. Pick the closest match maybe?");
}
// else exactly one file
File foundFile = foundFiles.iterator().next();
return Optional.of(foundFile);
}
}
And here are some test cases:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.Optional;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.google.common.io.Files;
/**
* Non-quite-unit tests for {#link CaseInsensitiveFileFinder} class.
*/
public class CaseInsensitiveFileFinderTest {
private static String APPENDABLE_NEW_TMP_DIR_PATH;
/**
* Create the files with different cases.
* #throws IOException
*/
#BeforeClass
public static void setup() throws IOException {
File newTmpDir = Files.createTempDir();
String newTmpDirPath = newTmpDir.getCanonicalPath();
final String appendableNewTmpDirPath;
String fileSeparator = System.getProperty("file.separator");
if (!newTmpDirPath.endsWith(fileSeparator)) {
appendableNewTmpDirPath = newTmpDirPath + fileSeparator;
}
else {
appendableNewTmpDirPath = newTmpDirPath;
}
CaseInsensitiveFileFinderTest.APPENDABLE_NEW_TMP_DIR_PATH = appendableNewTmpDirPath;
File foofileDotPng = new File(appendableNewTmpDirPath + "FOOFILE.PNG");
Files.touch(foofileDotPng);
assertTrue(foofileDotPng.isFile());
File barfileDotJpg = new File(appendableNewTmpDirPath + "BARFILE.JPG");
Files.touch(barfileDotJpg);
assertTrue(barfileDotJpg.isFile());
}
#AfterClass
public static void teardown() throws IOException {
File newTmpDir = new File(CaseInsensitiveFileFinderTest.APPENDABLE_NEW_TMP_DIR_PATH);
assertTrue(newTmpDir.isDirectory());
// delete even though directory isn't empty
FileUtils.deleteDirectory(newTmpDir);
}
#Test
public void findFooFilePngUsingLowercase() throws IOException {
CaseInsensitiveFileFinder fileFinder = new CaseInsensitiveFileFinder();
Optional<File> optFoundFile = fileFinder.findFileIgnoreCase(APPENDABLE_NEW_TMP_DIR_PATH, "foofile.png");
assertTrue(optFoundFile.isPresent());
File foundFile = optFoundFile.get();
assertTrue(foundFile.isFile());
assertEquals(APPENDABLE_NEW_TMP_DIR_PATH + "FOOFILE.PNG", foundFile.getCanonicalPath());
}
#Test
public void findBarFileJpgUsingLowercase() throws IOException {
CaseInsensitiveFileFinder fileFinder = new CaseInsensitiveFileFinder();
Optional<File> optFoundFile = fileFinder.findFileIgnoreCase(APPENDABLE_NEW_TMP_DIR_PATH, "barfile.jpg");
assertTrue(optFoundFile.isPresent());
File foundFile = optFoundFile.get();
assertTrue(foundFile.isFile());
assertEquals(APPENDABLE_NEW_TMP_DIR_PATH + "BARFILE.JPG", foundFile.getCanonicalPath());
}
#Test
public void findFileThatDoesNotExist() {
CaseInsensitiveFileFinder fileFinder = new CaseInsensitiveFileFinder();
Optional<File> optFoundFile = fileFinder.findFileIgnoreCase(APPENDABLE_NEW_TMP_DIR_PATH, "dne.txt");
assertFalse(optFoundFile.isPresent());
}
#Test
public void findFooFileUsingDirWithNoTrailingFileSeparator() throws IOException {
CaseInsensitiveFileFinder fileFinder = new CaseInsensitiveFileFinder();
String newDirPathWithNoTrailingFileSep = StringUtils.chop(APPENDABLE_NEW_TMP_DIR_PATH);
Optional<File> optFoundFile = fileFinder.findFileIgnoreCase(newDirPathWithNoTrailingFileSep, "FOOFILE.PNG");
assertTrue(optFoundFile.isPresent());
File foundFile = optFoundFile.get();
assertTrue(foundFile.isFile());
assertEquals(APPENDABLE_NEW_TMP_DIR_PATH + "FOOFILE.PNG", foundFile.getCanonicalPath());
}
}
Hope that helps.
Instead of returning t (the file extension) return the file Object. That way your certain that you have the correct file. If you don't want to return the file object return the file name with the extension.
public static File getPhotoFileExtension(int empKey){
try{
String[] types = {".jpg",".JPG",".png", ".PNG"};
for(String t : types)
{
String path = "/"+Common.PHOTO_PATH + empKey + t;
File f = new File(Sessions.getCurrent().getWebApp()
.getRealPath(path));
if(f.isFile())
return f;
}
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
With that NiMa Thr said, you can do what you are looking for with this code :
On Windows, if the file exists, with any case, it will return true. If the file doesn't exists, the canonical name will be the same, so it will return false.
On Linux, if the file exists with a different case, the canonical name will return this different name, and the method will return true.
public static boolean fileExistsCaseInsensitive(String path) {
try {
File file = new File(path);
return file.exists() || !file.getCanonicalFile().getName().equals(file.getName());
} catch (IOException e) {
return false;
}
}
So I have a directory in my local C drive.
C:/Search Files/Folder [number]/hello.txt
Inside Search Files I have four foldes named:
Folder 1
Folder 2
Folder 3
Folder 4
Inside Folder 1 I have a a file called hello.txt with some String in it.
What I want to do is grab the fileDirectory, fileName and fileContent and put it in a List of XMLMessage objects. I have pasted my main class and my XMLMessage POJO. When I run it, I am getting an indexOutOfBoundsException. I have been stuck for a couple hours now. I need another pair of eyes to look into this.
Thanks,
package org.raghav.stuff;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.io.FileUtils;
public class GetFile {
public static void main(String[] args) throws IOException {
File[] files = new File("C:\\Search Files").listFiles();
showFiles(files);
}
public static void showFiles(File[] files) throws IOException {
String line = null;
List<XMLMessage> xmlMessageList = new ArrayList<XMLMessage>();
int i = 0;
//XMLMessage folderFile = new XMLMessage();
try {
for (File file : files) {
if (file.isDirectory()) {
String fileName = file.getName();
System.out.print(fileName);
xmlMessageList.get(i).setFileName(fileName);
//folderFile.setFileName(fileName);
showFiles(file.listFiles()); // Calls same method again.
} else {
xmlMessageList.get(i).setFileDirectory(file.getName() + file.toString());
//folderFile.setFileDirectory(file.getName() + file.toString());
System.out.print("\tFile: " + file.getName()
+ file.toString());
// System.out.println("Directory: " + file.getName());
BufferedReader in = new BufferedReader(new FileReader(file));
while ((line = in.readLine()) != null) {
xmlMessageList.get(i).setFileContent(line);
// folderFile.setFileContent(line);
System.out.print("\t Content:" + line);
}
in.close();
System.out.println();
}
i++;
}
} catch (NullPointerException e) {
e.printStackTrace();
}
System.out.println(xmlMessageList.toString());
}
}
Here is the POJO:
package org.raghav.stuff;
public class XMLMessage {
private String fileDirectory;
private String fileName;
private String fileContent;
public final String FILE_NAME = "fileName";
public final String FILE_DIRECTORY = "fileDirectory";
public XMLMessage(String fileDirectory, String fileName, String fileContent) {
this.fileDirectory = fileDirectory;
this.fileName = fileName;
this.fileContent = fileContent;
}
public XMLMessage() {
}
public String getFileDirectory() {
return fileDirectory;
}
public void setFileDirectory(String fileDirectory) {
this.fileDirectory = fileDirectory;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileContent() {
return fileContent;
}
public void setFileContent(String fileContent) {
this.fileContent = fileContent;
}
public String toString(){
String returnString = "File Directory: " + fileDirectory + "\n" + "File Name" + fileName + "\n" + "File Content: " + fileContent;
return returnString;
}
/*public String createResponseFileName(String fileName){
int lastDot = fileName.lastIndexOf('.');
String responseFileName = fileName.substring(0, lastDot) + "Response" + fileName.substring(lastDot);
return responseFileName;
}*/
/*public String createResponseFileContent(String fileContent){
this.
}*/
}
You're never populating your list. I suspect you should actually have:
for (File file : files) {
XMLMessage message = new XMLMessage();
xmlMessageList.add(message);
if (file.isDirectory()) {
String fileName = file.getName();
System.out.print(fileName);
message.setFileName(fileName);
//folderFile.setFileName(fileName);
showFiles(file.listFiles()); // Calls same method again.
} else {
... etc, using message instead of xmlMessageList.get(i)
}
}
Then you don't need the i variable at all.
I think Jon Skeet is right.
you never populate your list.
you should use your constructor
XmlMessage m = new XMLMessage( fileDirectory, fileName,fileContent)
xmlMessageList.add(m);
I want to copy the directory structure without copying the content/files. I want to copy only folder structure.
I have written a sample program but it is also copying the content/files also.
import java.io.*;
import java.nio.channels.*;
#SuppressWarnings("unused")
public class CopyDirectory{
public static void main(String[] args) throws IOException{
CopyDirectory cd = new CopyDirectory();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String source = "C:\\abcd\\Documents\\1";
File src = new File(source);
String destination = "C:\\abcd\\Documents\\2";
File dst = new File(destination);
cd.copyDirectory(src, dst);
}
public void copyDirectory(File srcPath, File dstPath) throws IOException{
if (srcPath.isDirectory())
{
if (!dstPath.exists())
{
dstPath.mkdir();
}
String files[] = srcPath.list();
for(int i = 0; i < files.length; i++)
{
System.out.println("\n"+files[i]);
copyDirectory(new File(srcPath, files[i]), new File(dstPath, files[i]));
}
}
System.out.println("Directory copied.");
}
}
I am struck at this point.
Thank you.
This worked for me:
import java.io.File;
public class StartCloneFolderOnly {
/**
* #param args
*/
public static void main(String[] args) {
cloneFolder("C:/source",
"C:/target");
}
public static void cloneFolder(String source, String target) {
File targetFile = new File(target);
if (!targetFile.exists()) {
targetFile.mkdir();
}
for (File f : new File(source).listFiles()) {
if (f.isDirectory()) {
String append = "/" + f.getName();
System.out.println("Creating '" + target + append + "': "
+ new File(target + append).mkdir());
cloneFolder(source + append, target + append);
}
}
}
}
So if I'm right, you just want to copy the folders.
1.) Copy directory with sub-directories and files
2.) Place 1. wherever
3a.) Instantiate to list files in parent directory into an arrayList
3b.) Instantiate to list the new subfolders into an arrayList
3c.) Instantiate to list all files in each subfolder into their own arrayLists
4.) Use a for-loop to now delete every file within the new directory and subfolder
From this, you should have a copy of the new directory with all files removed.
import java.io.*;
import java.nio.channels.*;
#SuppressWarnings("unused")
public class CopyDirectory{
public static void main(String[] args) throws IOException{
CopyDirectory cd = new CopyDirectory();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String source = "C:\\abcd\\Documents\\1";
File src = new File(source);
String destination = "C:\\abcd\\Documents\\2";
File dst = new File(destination);
cd.copyDirectory(src, dst);
}
public void copyDirectory(File srcPath, File dstPath) throws IOException{
if (srcPath.isDirectory())
{
if (!dstPath.exists())
{
dstPath.mkdir();
}
String files[] = srcPath.list();
for(int i = 0; i < files.length; i++)
{
System.out.println("\n"+files[i]);
copyDirectory(new File(srcPath, files[i]), new File(dstPath, files[i]));
}
}
System.out.println("Directory copied.");
}
}
I'm downloading from FTP server and I don't know exactly how to check if file already exist. What I want to do is that I retrieve filname from FTP server and then compare it with all files in folder. If file already exists then it compares next FTP filename with all files in folder and so on.
I already did comparison and it's working if all files from folder have same name as files on FTP server but if I add some older file then it downloads all files once again and I don't want that.
Here is my scratch code:
String[] names = client.listNames();
File folder = new File("c:\\test\\RTR_ZIP\\");
String[] filename = folder.list();
for (;i<names.length;i++) {
name = names[i];
exists=false;
if (name.contains(".zip")) {
if (filename.length == 0) {
new_file = new FileOutputStream("C:\\test\\RTR_ZIP\\" + name);
client.retrieveFile(name, new_file);
j++;
exists=true;
} else {
for (;k<filename.length;k++) {
name = names[i];
i++;
name1=filename[k];
// CHECK IF FILE EXISTS
if (!name.equals(name1)) {
new_file = new FileOutputStream("C:\\test\\RTR_ZIP\\" + name);
client.retrieveFile(name, new_file);
j++;
exists=true;
}
}
}//else
}//if contains .zip
}//for
Thanks in advance.
If your ftp server supports XCRC command it could be possible to compare checksum (CRC32) of local and remote file.
You could iterate all files in the folder and compare its crc with local one.
import java.io.File;
import java.io.IOException;
import java.net.SocketException;
import java.util.Scanner;
import org.apache.commons.io.FileUtils;
import org.apache.commons.net.ftp.FTPClient;
public class DownloadFile {
private FTPClient client = new FTPClient();
public void connect() throws SocketException, IOException {
client.connect("127.0.0.1");
client.login("user", "password");
}
public boolean hasXCRCSupport() throws IOException {
client.sendCommand("feat");
String response = client.getReplyString();
Scanner scanner = new Scanner(response);
while(scanner.hasNextLine()) {
String line = scanner.nextLine();
if(line.contains("XCRC")) {
return true;
}
}
return false;
}
public boolean isSameFile() throws IOException {
if(hasXCRCSupport()) {
File file = new File("D:/test.txt");
String localCRC = Integer.toHexString((int) FileUtils.checksumCRC32(file)).toUpperCase();
client.sendCommand("XCRC /test.txt");
String response = client.getReplyString().trim();
System.out.println(response);
if(response.endsWith(localCRC)) {
return true;
}
}
return false;
}
public void logout() throws IOException {
client.logout();
}
public static void main(String[] args) throws SocketException, IOException {
DownloadFile downloadFile = new DownloadFile();
downloadFile.connect();
if(downloadFile.isSameFile()) {
System.out.println("remote file is same as local");
}
downloadFile.logout();
}
}
You should check for existence using java.io.File.exists and java.io.File.isFile()|isDirectory().
Maybe it will be useful to somebody with same problem. I made program by this method:
package javaapplication2;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.net.ftp.*;
public class DLFile {
public static void saveZIP() throws Exception {
FTPClient client = new FTPClient();
FileOutputStream new_file = null;
String server = "server";
String user = "user";
String pass = "pass";
String name = "";
String downloadFolder = "download_folder";
Boolean exists = null;
int i=0;
int j=0;
client.connect(server);
client.login(user,pass);
client.changeWorkingDirectory("/rtr/");
//read ftp content
String[] names = client.listNames();
File folder = new File(downloadFolder);
String[] filename = folder.list();
for (;i<names.length;i++) {
name = names[i];
exists=false;
if (name.contains(".zip")) {
if (filename.length == 0) {
new_file = new FileOutputStream(downloadFolder + name);
client.retrieveFile(name, new_file);
j++;
exists=true;
} else {
//CHECK IF FILE EXISTS
if (!new File(downloadFolder + name).exists()) {
new_file = new FileOutputStream(downloadFolder + name);
client.retrieveFile(name, new_file);
j++;
exists=true;
}
}//else
}//if contains .zip
}//for
if (exists = true) {
System.out.println("Downloading ZIP files: Downloaded " + j + " files");
} else System.out.println("Downloading ZIP files: Files already exist.");
client.logout();
}
}