java.io.File constructor behaviour or perhaps multithreading issue? - java

I have the following code:
class Abcd{
//wired by spring to give the directory filePath ="/var/tmp/"
private String filePath;
public void myMethod(String id, String date){
filePath= filePath+ id+ "_" + date;
File f = new File(filePath);
if(f.exists){//Do something}
else{
System.out.println("File not found at file path:"+filePath);
}
}
}
The above code is behaving weird , intermittently the filePath contains all the files of directory /var/tmp/ . So , if /var/tmp directory contains two files called "id1_01012017" and "id2_10102017".
This is the intermittent output
File not found at file path:/var/tmp/id1_01012017id2_10102017
Am unable to figure out whats happening

The best way to do this is to maintain that filePath remains immutable. You will find that if you change this line:
filePath = filePath + id + "_" + date;
to the following:
String tempFilePath = filePath + id + "_" + date;
and operate on tempFilePath instead of filePath, your code will become thread-safe and work as expected.

Related

Java parses File.separator as %5c which isn't recognized as legit file path

I'm not really sure when it started, but my Selenium framework stopped accepting path names with File.separator, I must use backslashes or I can't upload files.
If I type path like this:
String DOCX = "uploads" + File.separator + "mock" + File.separator + "document_donotparse.docx";
I get such an error:
invalid argument: File not found : C:\XXX\Arbeit\tests\build\resources\test\uploads%5cmock%5cdocument_donotparse.docx
So basically File.separator gets translated to %5c
Now this is the code I am using:
public void uploadFiles(#NotNull List<String> filenames, By input, By progressBar, FileType fileType) {
log.trace("Uploading files: {}", filenames);
getExistingElement(input).sendKeys(Utils.parseFilenamesForMultipleUpload(filenames));
throwIfParsingFailed(fileType);
waitForAllElementsToDisappear(progressBar);
}
and since I also need to upload multiple files at once, I need the util function:
public String parseFilenamesForMultipleUpload(#NotNull Collection<String> filenames) {
return String.join(" \n ", filenames
.stream()
.map(filename -> new File(Objects.requireNonNull(
Utils.class.getClassLoader().getResource(filename)).getFile()).getAbsolutePath())
.toList());
}
The only thing that worked so far was basically changing code to use "normal" backslashes:
String DOCX = "uploads/mock/document_donotparse.docx";
I would, however, like to use File.separator back again.
Also I am having no problems at all when reading json or properties files, for which paths are also separated with File.separator, so the problem must lie somewhere with the upload code.
Thanks to #hiren I pinpointed that the place where parsing to %5c occured was parseFilenamesForMultipleUpload. So I added URLDecoder to get rid of percentages and created my own method removePath to remove path part of file regardless of type of file separator.
Here is the the code:
parseFilenamesForMultipleUpload is very similiar I just added more mappings to make it cleaner and added mapping through decodeQuery method, which simply translates percentages.
public String parseFilenamesForMultipleUpload(#NotNull Collection<String> filenames) {
return filenames
.stream()
.map(Utils::getFile)
.map(File::getPath)
.map(Utils::decodeQuery)
.collect(Collectors.joining("\n"));
}
Utils#getFile is simply some code from previous version of parseFilenamesForMultipleUpload method extracted fo clarity:
#Contract("_ -> new")
private #NotNull File getFile(String filename) {
return new File(Objects.requireNonNull(Utils.class.getClassLoader().getResource(filename)).getFile());
}
I then map it again with File#getPath instead of File#AbsolutePath like before, and finally decodeQuery translates percentage style.
Utils#decodeQuery:
public String decodeQuery(String query) {
return URLDecoder.decode(query, StandardCharsets.UTF_8);
}
And finally I join them with a newline character.
Then, to be able to extract filename from filepath I created such method:
public String removePath(#NotNull String filepath) {
for (char c : new char[]{'/', '\\', File.separatorChar, File.pathSeparatorChar}) {
filepath = cutFilePath(filepath, c);
}
return filepath;
}
where cutFilePath is:
private #NotNull String cutFilePath(#NotNull String filepath, char delimiter) {
int charIndex = filepath.lastIndexOf(delimiter);
return charIndex > -1 ? filepath.substring(charIndex + 1) : filepath;
}
Everything is working :)

Cannot create file with Java using the Parent and Child parameters of the new File constructor

I am trying to create a file using Java. I want to create this file in a sub-folder of my "Documents" directory. I want this sub-folder to be based today's date.
I thought I new how to use the File class and file.mkdirs() method properly, but I guess I don't.
Here is what I have:
public class FileTest {
private static final String sdfTimestampFormat = "yyyy-MM-dd HH:mm:ss Z";
private static final SimpleDateFormat timestampSDF = new SimpleDateFormat(sdfTimestampFormat);
private static final String sdfDirFormat = "yyyy-MM-dd";
private static final SimpleDateFormat dirSDF = new SimpleDateFormat(sdfDirFormat);
public static void test() throws FileNotFoundException, IOException{
Date rightNow = new Date();
String data = "the quick brown fox jumps over the lazy dog";
String path = System.getProperty("user.home");
String filename = "file.txt";
String directory_name = path + System.getProperty("file.separator") + "Documents" + System.getProperty("file.separator") + dirSDF.format(rightNow);
File file = new File(directory_name, filename);
if(file.mkdirs()){
String outstring = timestampSDF.format(rightNow) + " | " + data + System.getProperty("line.separator");
FileOutputStream fos = new FileOutputStream(file, true);
fos.write(outstring.getBytes());
fos.close();
}
}
}
What is happening is that the following directory is created:
C:\Users\<username>\Documents\2018-08-03\file.txt\
I was under the impression that the Parent parameter of the new File constructor was the base directory, and the Child paramater of the new File constructor was the file itself.
Is this not the case? Do I need two File objects, one for the base directory and another for the file?
What I want is this:
C:\Users\<username>\Documents\2018-08-03\file.txt
Thanks.
mkdirs() will do directories (if they don't exist) for each element in your path.
So you can use file.getParentFile().mkdirs() to not make a directory for your file.txt
Edit: Something to consider
mkdirs() only returns true if it actually created directories. If they already existed or there was a problem creating them it will return false
Since you are trying to run this multiple times to append to your text your logic will not run inside your if-statement
I would change it to:
boolean created = true;
if(!file.getParentFile().exists()) {
created = file.getParentFile().mkdirs();
}
if (created) {
String outstring = timestampSDF.format(rightNow) + " | " + data + System.getProperty("line.separator");
FileOutputStream fos = new FileOutputStream(file, true);
fos.write(outstring.getBytes());
fos.close();
}

Get character from string between similar sings

I am trying to get a path of an image in my android device, such as:
/ storage/emulated/0/DCIM/Camera/NAME.jpg
and just trying to grab the image name, but i can.
I am trying with ...
String s = imagePath;
Where the route imagePath
            
s = s.substring (s.indexOf ("/") + 1);
s.substring s = (0, s.indexOf () ".");
Log.e ("image name", s);
it returns me :
storage/emulated/0/DCIM/Camera/NAME.jpg
and i only want
NAME.jpg
You need String.lastIndexOf():
String imagePath = "/path/to/file/here/file.jpg";
String path = imagePath.substring(imagePath.lastIndexOf('/') + 1);
You can do something like that:
File imgFile = new File(imagePath);
String filename = imgFile.getFilename();
This saves you a lot of hassle when you want to use your application cross-platform, because on Linux you have "/" as path delimiters and "\" on Windows
In case, if you are dealing with File object, then you can use its predefined method getName().
i.e.:
File mFile = new File("path of file");
String filename = mFile.getName();

Two similar copy codes with Java, two behaviors

So I wanted to implement a function that copies a file into a new file of which I'll specify the directory (I'll create it) and then, as I found on stackoverflow, use the Files.copy function of apache.commons to do the trick.
My problem is the following : I write two codes, one that works and the other don't, except they are so similar I seem not to capture the difference...
Here's the code for the first method :
public static void copyToFile2 (String firmFolderName, String allFirmsFolderName, String copy_file_name, String copied_file_name) throws IOException {
File from = new File(copied_file_name) ;
String pathOfDirectoryOfToFile= "Folder/" + allFirmsFolderName +"/" + firmFolderName ;
//String pathOfDirectoryOfToFile = "Folder/fomrs/firm/" ;
String pathOfToFile = pathOfDirectoryOfToFile + "/" + copy_file_name ;
(new File(pathOfDirectoryOfToFile)).mkdir();
File to = new File(pathOfToFile) ;
Files.copy( from.toPath(), to.toPath() );
}
In this one, I have to specify few parameters that will forge a path to a directory, create that directory and finally create the copy file in there. It throws a NoSuchFileException, and while I know the file doesn't not exist, I thought it might be nice and create it itself, but since it didn't : I went ahead and added to.createNewFile(); right after the to file instanciation to make sure, thus I'll have the following code :
(new File(pathOfDirectoryOfToFile)).mkdir();
File to = new File(pathOfToFile) ;
to.createNewFile();
Files.copy( from.toPath(), to.toPath() );
With this one, I get an IOException stating that the specified access path is not found !
Second method :
public static void copyToFile1 (String firmFolderName, String allFirmsFolderName, String copy_file_name, String copied_file_name) throws IOException {
File from = new File(copied_file_name) ;
String pathOfDirectoryOfToFile= "Folder/" + allFirmsFolderName +"/" + firmFolderName +"/" ;
String pathOfToFile = pathOfDirectoryOfToFile + "/" + copy_file_name ;
(new File("Folder/mdjs55/")).mkdir();
File to = new File("Folder/mdjs55/tm.jsp" ) ;
Files.copy( from.toPath(), to.toPath() );
}
In this one works fine.
So what is it ? The only difference I can not is that the path in the copyToFile2 is dynamic and in the second static, but how is that supposed to be a problem ? For what I know it's merely a string that's being build...
P.S : I used System.out.println(to.toPath()) to check out the path for that, it's well constructed.
Thanks in advance for your help.
The path in the second example is shorter. mkdir() will only create one sub-directory so if you go two sub-directories it will fail and when you try to use a file in that directory it will also fail.
I suspect what you want is mkdirs() which creates multiple-levels of directories as required.
This
String pathOfDirectoryOfToFile= "Folder/" + allFirmsFolderName +"/" + firmFolderName +"/" ;
String pathOfToFile = pathOfDirectoryOfToFile + "/" + copy_file_name ;
looks suspicious. It produces
"Folder/" + allFirmsFolderName +"/" + firmFolderName +"//" + copy_file_name ;

Generate filename for a copied file

I am looking to get similar behaviour to what you get in Windows when you copy and paste a file in the same directory.
For e.g, if you've copy/paste a file called foo.txt, it will create foo Copy.txt and if you paste it once more, it creates foo Copy(2).txt and if you copy/paste foo Copy.txt, foo Copy Copy.txt is created.
Is there a Java utility function that does this? I've looked at File.createTempFile but the filename it generates is too long and contains a UID-like substring.
By using the FileChooser in combination with the "showSaveDialog"-method you will get the result you want, because java is then using the OS behaviour for existing files.
Sometimes, you just have to do the work first, it will give you an appreciation for the API. Then you can write your own utility methods
File original = new File("build.xml");
String path = original.getAbsoluteFile().getParent();
String name = original.getName();
String ext = name.substring(name.indexOf("."));
name = name.substring(0, name.indexOf("."));
name = path + File.separator + name;
int index = 1;
File copy = new File(name + " (" + index + ")" + ext);
while (copy.exists()) {
index++;
copy = new File(name + " (" + index + ")" + ext);
}
System.out.println(copy);

Categories

Resources