How can I recursively FTP a directory structure using Jsch? [duplicate] - java

This question already has answers here:
Transfer folder and subfolders using ChannelSftp in JSch?
(3 answers)
Closed 5 years ago.
I'm trying to traverse a directory and upload all contents and directories in the same structure.
This is an example structure:
Dir1/
....Dir1_1/
....Dir1_2/
........Dir1_2_1/
............file.txt
Dir2/
....file.txt
....file2.txt
Dir3/
Dir4/
index.html
index.css
example.file
I've tried the following:
private void ftpFiles(File[] files, ChannelSftp channelSftp) throws SftpException, FileNotFoundException {
for (File file : files) {
System.out.println("Uploading: " + file.getName());
if (file.isDirectory()) {
System.out.println(file.getName() + " is a directory");
SftpATTRS attrs;
try {
channelSftp.stat(file.getName());
} catch (Exception e) {
System.out.println(file.getName() + " does not exist. Creating it...");
channelSftp.mkdir(file.getName());
}
channelSftp.cd(file.getName());
this.ftpFiles(file.listFiles(), channelSftp);
} else {
channelSftp.put(new FileInputStream(file), file.getName());
}
}
}
I'm taking an array of top level files, and recursively going down each one.
The problem is once I hit the first directory and cd into it, all further files and directories are inside of this.
Example: /Dir1/Dir1_1/Dir1_2/Dir1_2_1/Dir2/Dir3/Dir4/...etc
How can I do a ../ with my channel while calling this recursively?

Maybe something like (pseudo code):
List<Files> directories = new ArrayList<> ();
if (file is directory) directories.add(file);
else dowloadFile();
for (File f : directories) {
cd(f);
ftpFiles(listFiles());
cd(..);
}

Related

when using a zip file as a FileSystem the zip file is not being update

I want to manipulate a jar using the standard nio Files and Paths methods. So, Java has a way to do this by creating a zip FileSystem:
try {
zipFS = FileSystems.newFileSystem(zipDisk, zipFSproperties);
} catch(Exception e) {
System.out.println(e.getMessage());
}
My test program uses an existing jar file as a FileSystem and it lists the entries contained in the jar. All that works great. I then copy a new file into the jar and list the entries again. And just as you would expect, the list now contains the newly added file. The problem is after the program closes, I open up the jar file that the jar filesystem is based upon and it doesn't have the new entry added to it. So that's my question! Shouldn't the jar file itself be changed when I add a new entry. I don't know of any commands I can issue the would cause the zip FileSystem to update to the actual jar file that the zip FileSystem wraps. Am I reading more into a FileSystem; are changes in the zip filesystem suppose to cause the corresponding backend zip file to be updated.
code:
public class Main {
public static void main(String[] args) throws IOException {
ZipFileSystem zipFS = new ZipFileSystem("C:\\Temp\\mylibrary\\build\\outputs\\jar\\temp\\mylibrary-debug.zip");
Stream<Path> paths = Files.find(zipFS.zipFS.getRootDirectories().iterator().next().getRoot(),10, (path, basicFileAttributes) -> {
return !Files.isDirectory(path);
});
paths.forEach( path ->
System.out.println ("zip contains entry: " + path)
);
File file = new File("C:\\Temp\\mylibrary\\src\\main\\java\\com\\phinneyridge\\android\\myLib.java");
System.out.println("copying " + file.getPath());
Path outPath = zipFS.zipFS.getPath("myLib.java");
Files.copy (file.toPath(), outPath, StandardCopyOption.REPLACE_EXISTING);
paths = Files.find(zipFS.zipFS.getPath(""),10, (path, basicFileAttributes) -> {
return !Files.isDirectory(path);
});
paths.forEach( path ->
System.out.println ("zip contains entry: " + path)
);
}
}
I added code that shows me accessing a zip file, listing the current entries it contains, adding a new entry (via file copy), and lastly listing the contents again. All of this code works correctly. What doesn't work is that the changes to the zip filesystem don't get incorporated back into the zip file when the application ends. I was surprised that the zip file didn't get updated, but I'm now under the opinion, that it's working as it is intended to work; not doing what I wanted it to do, but that's okay. I can't find any documentation that says it would update the jar file that the FileSystem object originated from. So I'm basically asking is that the correct behavior, or is there something I'm entirely missing to cause the zip FileSystem object to update the Zip file?
Here's the code when I tried Dunc suggestion:
public static void main(String[] args) throws IOException {
ZipFileSystem zipFS = new ZipFileSystem("C:\\Temp\\mylibrary\\build\\outputs\\jar\\temp\\mylibrary-debug.zip");
try (FileSystem fs = zipFS.zipFS) {
try (Stream<Path> paths = Files.find(zipFS.zipFS.getRootDirectories().
iterator().next().getRoot(), 10, (path, basicFileAttributes) -> {
return !Files.isDirectory(path);
})) {
paths.forEach(path ->
System.out.println("zip contains entry: " + path)
);
}
File file = new File("C:\\Temp\\mylibrary\\src\\main\\java\\com\\phinneyridge\\android\\myLib.java");
System.out.println("copying " + file.getPath());
Path outPath = fs.getPath("myLib.java");
Files.copy(file.toPath(), outPath, StandardCopyOption.REPLACE_EXISTING);
try (Stream<Path> paths = Files.find(zipFS.zipFS.getRootDirectories().
iterator().next().getRoot(), 10, (path, basicFileAttributes) -> {
return !Files.isDirectory(path);
})) {
paths.forEach(path ->
System.out.println("zip contains entry: " + path)
);
}
} catch (Exception e) {
System.out.println("FileSystem Error: " + e.getClass().getName() + " - " + e.getMessage());
e.printStackTrace();
}
}
}
And by the way ZipFileSystem is a wrapper class around the FileSystem. I'll post that code too, incase that's where I 'm doing something wrong.
public class ZipFileSystem {
FileSystem zipFS;
Path zipFSPath;
/**
* Constructor for a ZipFile object
* #param zipFilePath string representing the path to the zipfile. If the path doesn't exist,
* the zip file will be automatically created. If the path exist, it must be a file (not
* a directory) and it must be a valid zip file
*/
public ZipFileSystem(String zipFilePath) {
Map<String, String> zipFSproperties = new HashMap<>();
/* set create to true if you want to create a new ZIP file */
zipFSproperties.put("create", "true");
/* specify encoding to UTF-8 */
zipFSproperties.put("encoding", "UTF-8");
/* Locate File on disk for creation */
URI zipFileUri = new File(zipFilePath).toURI();
URI zipDisk = URI.create("jar:" + zipFileUri);
zipFSPath = Paths.get(zipFileUri);
if (!Files.exists(zipFSPath)) {
try {
createEmptyZipFile(zipFSPath);
} catch (Exception e ) {
System.out.println(e.getMessage());
}
} else {
if (Files.isDirectory(zipFSPath)) {
} else {
try {
// let's open it, which will verify if it's a valid zip file
ZipFile zipFile = new ZipFile(zipFilePath);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
try {
zipFS = FileSystems.newFileSystem(zipDisk, zipFSproperties);
} catch(Exception e) {
System.out.println(e.getMessage());
}
try {
listFiles(zipFS.getPath("/"));
} catch (IOException e) {
e.printStackTrace();
}
}
The correct way to open a zip from a Path - and create if not exists - is:
Path zip = Path.of("/Somepath/to/xyz.zip");
Map<String, String> env = Map.of(
"create", "true"
// other args here ...
);
try (FileSystem fs = FileSystems.newFileSystem(zip, env)) {
// code to read/update here
}
You have not closed any files or streams properly so your changes are probably not flushed back to the file system and will keep hold of file handles which block some operations.
Use try with resources for every operation which will manage the modifications to zip filesystem as well as closing each Stream<Path> from Files.find, and check other places such as createEmptyZipFile for the same problem:
try (FileSystem fs = ... ) {
try (Stream<Path> paths = Files.find(...) ) {
}
Files.copy( ... );
try (Stream<Path> paths = Files.find(...) ) {
}
}
The process cannot access the file because it is being used by another process
You have unnecessary code ZipFile zipFile = new ZipFile(zipFilePath) which tests the zip is valid and you do not call close(), so it will prevent the zip changes being written back. The check can safely be deleted (as FileSystems.newFileSystem does same) or must be wrapped in try() {} so that zipFile is closed before your edits to the zip filesystem.

Using the Files.move creates a new "file" file type rather than moving the file to a directory

I am trying to make a program that extracts multiple MP4 files from there individual folders and places them in a folder that is already created (code has been changed slightly so that it doesn't mess up any more of the MP4s, rather dummy text files).
I have managed to get so far as to list all folders/files in the specified folder however am having trouble moving them to a directory.
static File dir = new File("G:\\New Folder");
static Path source;
static Path target = Paths.get("G:\\gohere");
static void showFiles(File files[]) {
for (File file : files) { // Loops through each file in the specified directory in "dir" variable.
if (file.isDirectory()) { // If the file is a directory.
File[] subDir = file.listFiles(); // Store each file in a File list.
for (File subFiles : subDir) { // Loops through the files in the sub-directory.
if (subFiles.getName().endsWith(".mp4")) { // if the file is of type MP4
source = subFiles.toPath(); // Set source to be the abs path to the file.
System.out.println(source);
try {
Files.move(source, target);
System.out.println("File Moved");
} catch (IOException e) {
e.getMessage();
}
}
}
} else {
source = file.toPath(); // abs path to file
try {
Files.move(source, target);
System.out.println("File moved - " + file.getName());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
showFiles(dir.listFiles());
}
The problem is when I go to move the file from the source folder to the target, it removes or converts the target.
Files.move isn't like the command line. You're programming. You have to spell things out. You're literally asking Files.move to make it so that target (here, G:\GoHere) will henceforth be the location for the file you are moving. If you intended: No, the target is G:\GoHere\TheSameFileName then you have to program this.
Separately, your code is a mess. Stop using java.io.File and java.nio.Path together. Pick a side (and pick the java.nio side, it's an newer API for a good reason), and do not mix and match.
For example:
Path fromDir = Paths.get("G:\\FromHere");
Path targetDir = Paths.get(G:\\ToHere");
try (DirectoryStream ds = Files.newDirectoryStream(fromDir)) {
for (Path child : ds) {
if (Files.isRegularFile(child)) {
Path targetFile = targetDir.resolve(child.getFileName());
Files.move(child, targetFile);
}
}
}
resolve gives you a Path object that is what you need here: The actual file in the target dir.

fastest way to find list of files in a huge windows directory tree

I have a windows directory tree with about 1,000,000 files inside.
I have a text file that i read in Java, contains some file names (about 100,000), and I want to check for every file name - if it exists in the directory (if yes - give me a full path of the file).
Already tried those options:
1.
File folder = new File("your/path");
File[] listOfFiles = folder.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
System.out.println("File " + listOfFiles[i].getName());
} else if (listOfFiles[i].isDirectory()) {
System.out.println("Directory " + listOfFiles[i].getName());
}
}
2.
public void func(String path, String name)
{
Path folder = Paths.get(path);
try (DirectoryStream<Path> stream = Files.newDirectoryStream(folder))
{
for (Path entry : stream)
{
if(Files.isDirectory(entry))
{
func(entry.toString(), name);
}
else
{
if(FilenameUtils.removeExtension(entry.getFileName().toString()).equals(name))
{
System.out.println(entry);
}
}
}
}
catch (IOException ex) {
// An I/O problem has occurred
}
}
So far all those options to do so are very slow.
As I guess, although all the files are in the same logic place, actually every file is saved in another place in the hard drive, so all those IO calls take too much time.
Another idea that i found here is ISearchFolderItemFactory interface, but I found documentation for it only in C++, not in Java.
Maybe I can implement a pre-sort or something, to put all the files really together in the hd, sorted by name, and then to use some hash method to find name by name?
Need some help...

Files.newDirectoryStream(path) does not return files recursively [duplicate]

This question already has answers here:
Recursively list all files within a directory using nio.file.DirectoryStream;
(9 answers)
Closed 6 years ago.
I m expecting to see a list of all files located under path d:/test folder. However, I can only get the files directly under that folder, but not recursively.
Code:
String folder = "D:/test";
Path path = fs.getPath(folder);
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path)) {
for (Path p : directoryStream) {
System.out.println(p.getFileName());
}
} catch (IOException e) {
e.printStackTrace();
}
result:
a.txt
folder
folder structure:
Another way to this extending your own logic :
public static void printFileNamesRecursively(String path){
Path yourPath = FileSystems.getDefault().getPath(path);
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(yourPath)) {
for (Path p : directoryStream) {
System.out.println(p.getFileName());
if(p.toFile().isDirectory()){
printFileNamesRecursively(p.toString());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
The Files::newDirectoryStream are meant to behave like that. If you want to recursively retrieve all directories and files in the given directory and its sub-directories, you will need Files::walk or Files::walkFileTree. For example (I assume you use Java 8):
Path path = //...
try {
Files.walk(path).map(Path::getFileName).forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
This is the right behavior for DirectoryStream. Instead, You can use org.apache.commons.io.FileUtils to enumerate the files recursively.

Rename all files in a folder using java [duplicate]

This question already has answers here:
Rename a file using Java
(15 answers)
Closed 8 years ago.
How can we rename all files in a folder using java?
C:/temp/pictures/1.jpg
C:/temp/pictures/2.jpg
C:/temp/pictures/3.jpg
C:/temp/pictures/4.jpg
C:/temp/pictures/5.jpg
Rename to
C:/temp/pictures/landscape_1.jpg
C:/temp/pictures/landscape_2.jpg
C:/temp/pictures/landscape_3.jpg
C:/temp/pictures/landscape_4.jpg
C:/temp/pictures/landscape_5.jpg
Kind regards
Take a look at below code which check file in the folder and rename it.
File dir = new File("D:/xyz");
if (dir.isDirectory()) { // make sure it's a directory
for (final File f : dir.listFiles()) {
try {
File newfile =new File("newfile.txt");
if(f.renameTo(newfile)){
System.out.println("Rename succesful");
}else{
System.out.println("Rename failed");
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
I Hope It Will Help You

Categories