I have this code here that saves bitmaps of images as a GIF file called test, but everytime the user saves it as test.gif so its constantly overwriting.
What are some ways to avoid overweriting and generate a new filename everytime programmatically?
if(imagesPathList !=null){
if(imagesPathList.size()>1) {
Toast.makeText(MainActivity.this, imagesPathList.size() + " no of images are selected", Toast.LENGTH_SHORT).show();
File sdCard = Environment.getExternalStorageDirectory();
File dir = new File (sdCard.getAbsolutePath() + "/dir1/dir2");
dir.mkdirs();
File file = new File(dir, "test.gif");
try{
FileOutputStream f = new FileOutputStream(file);
f.write(generateGIF(list));
} catch(Exception e) {
e.printStackTrace();
}
A quick and dirty solution is to put the system time in the filename:
File file = new File(dir, "test_" + System.currentTimeMillis() +".gif");
As long as that method isn't executed at the exact same millisecond, you won't have duplicates.
You can use java.io.File.createTempFile("test", ".gif", dir)
This creates unique filename but they might get significantly long after some time.
Alternatively you can create a method that creates unique filesnames yourself:
private File createNewDestFile(File path, String prefix, String suffix) {
File ret = new File(path, prefix + suffix);
int counter = 0;
while (ret.exists()) {
counter++;
ret = new File(path, prefix + "_" + counter + suffix);
}
return ret;
}
Instead of
File file = new File(dir, "test.gif");
you call
File file = createNewDestFile(dir, "test", ".gif");
This is not thread safe. For that you need a more sophisticated method (e.g. synchronize it and create a FileOutputStream instead of a File which is creating the file already before another call checks of the method checks its existence).
Related
I read this question here How to create a file in a directory in java?
I have a method that creates a QR Code. The method is called several times, depends on user input.
This is a code snippet:
String filePath = "/Users/Test/qrCODE.png";
int size = 250;
//tbd
String fileType = "png";
File myFile = new File(filePath);
The problem: If the user types "2" then this method will be triggered twice.
As a result, the first qrCODE.png file will be replaced with the second qrCODE.png, so the first one is lost.
How can I generate more than one qr code with different names, like qrCODE.png and qrCODE(2).png
My idea:
if (!myFile.exists()) {
try {
myFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
Any tips?
EDIT: I solved it by using a for loop and incrementing the number in the filename in every loop step.
You can create more files eg. like follows
int totalCount = 0; //userinput
String filePath = "/Users/Test/";
String fileName= "qrCODE";
String fileType = "png";
for(int counter = 0; counter < totalCount; counter++){
int size = 250;
//tbd
File myFile = new File(filePath+fileName+counter+"."+fileType);
/*
will result into files qrCODE0.png, qrCODE1.png, etc..
created at the given location
*/
}
Btw to add check if file exists is also good point.
{...}
if(!myFile.exists()){
//file creation
myFile.createNewFile()
}else{
//file already exists
}
{...}
Your idea of solving the problem is a good one. My advice is to break up the filePath variable into a few variables in order to manipulate the file name easier. You can then introduce a fileCounter variable that will store the number of files created and use that variable to manipulate the name of the file.
int fileCounter = 1;
String basePath = "/Users/Test/";
String fileName = "qrCODE";
String fileType = ".png";
String filePath = basePath + fileName + fileType;
File myFile = new File(filePath);
You can then check if the file exists and if it does you just give a new value to the filePath variable and then create the new file
if(myFile.exists()){
filePath = basePath + fileName + "(" + ++fileCounter + ")" + fileType;
myFile = new File(filePath);
}
createFile(myFile);
And you're done!
You can check /Users/Test direcroty before create file.
String dir = "/Users/Test";
String pngFileName = "qrCode";
long count = Files.list(Paths.get(dir)) // get all files from dir
.filter(path -> path.getFileName().toString().startsWith(pngFileName)) // check how many starts with "qrCode"
.count();
pngFileName = pngFileName + "(" + count + ")";
The condition is if the directory exists it has to create files in that specific directory without creating a new directory.
The below code only creates a file with the new directory but not for the existing directory . For example the directory name would be like "GETDIRECTION":
String PATH = "/remote/dir/server/";
String fileName = PATH.append(id).concat(getTimeStamp()).append(".txt");
String directoryName = PATH.append(this.getClassName());
File file = new File(String.valueOf(fileName));
File directory = new File(String.valueOf(directoryName));
if (!directory.exists()) {
directory.mkdir();
if (!file.exists() && !checkEnoughDiskSpace()) {
file.getParentFile().mkdir();
file.createNewFile();
}
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(value);
bw.close();
Java 8+ version:
Files.createDirectories(Paths.get("/Your/Path/Here"));
The Files.createDirectories() creates a new directory and parent directories that do not exist. This method does not throw an exception if the directory already exists.
This code checks for the existence of the directory first and creates it if not, and creates the file afterwards. Please note that I couldn't verify some of your method calls as I don't have your complete code, so I'm assuming the calls to things like getTimeStamp() and getClassName() will work. You should also do something with the possible IOException that can be thrown when using any of the java.io.* classes - either your function that writes the files should throw this exception (and it be handled elsewhere), or you should do it in the method directly. Also, I assumed that id is of type String - I don't know as your code doesn't explicitly define it. If it is something else like an int, you should probably cast it to a String before using it in the fileName as I have done here.
Also, I replaced your append calls with concat or + as I saw appropriate.
public void writeFile(String value){
String PATH = "/remote/dir/server/";
String directoryName = PATH.concat(this.getClassName());
String fileName = id + getTimeStamp() + ".txt";
File directory = new File(directoryName);
if (! directory.exists()){
directory.mkdir();
// If you require it to make the entire directory path including parents,
// use directory.mkdirs(); here instead.
}
File file = new File(directoryName + "/" + fileName);
try{
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(value);
bw.close();
}
catch (IOException e){
e.printStackTrace();
System.exit(-1);
}
}
You should probably not use bare path names like this if you want to run the code on Microsoft Windows - I'm not sure what it will do with the / in the filenames. For full portability, you should probably use something like File.separator to construct your paths.
Edit: According to a comment by JosefScript below, it's not necessary to test for directory existence. The directory.mkdir() call will return true if it created a directory, and false if it didn't, including the case when the directory already existed.
Trying to make this as short and simple as possible. Creates directory if it doesn't exist, and then returns the desired file:
/** Creates parent directories if necessary. Then returns file */
private static File fileWithDirectoryAssurance(String directory, String filename) {
File dir = new File(directory);
if (!dir.exists()) dir.mkdirs();
return new File(directory + "/" + filename);
}
I would suggest the following for Java8+.
/**
* Creates a File if the file does not exist, or returns a
* reference to the File if it already exists.
*/
public File createOrRetrieve(final String target) throws IOException {
final File answer;
Path path = Paths.get(target);
Path parent = path.getParent();
if(parent != null && Files.notExists(parent)) {
Files.createDirectories(path);
}
if(Files.notExists(path)) {
LOG.info("Target file \"" + target + "\" will be created.");
answer = Files.createFile(path).toFile();
} else {
LOG.info("Target file \"" + target + "\" will be retrieved.");
answer = path.toFile();
}
return answer;
}
Edit: Updated to fix bug as indicated by #Cataclysm and #Marcono1234. Thx guys:)
code:
// Create Directory if not exist then Copy a file.
public static void copyFile_Directory(String origin, String destDir, String destination) throws IOException {
Path FROM = Paths.get(origin);
Path TO = Paths.get(destination);
File directory = new File(String.valueOf(destDir));
if (!directory.exists()) {
directory.mkdir();
}
//overwrite the destination file if it exists, and copy
// the file attributes, including the rwx permissions
CopyOption[] options = new CopyOption[]{
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES
};
Files.copy(FROM, TO, options);
}
Simple Solution using using java.nio.Path
public static Path createFileWithDir(String directory, String filename) {
File dir = new File(directory);
if (!dir.exists()) dir.mkdirs();
return Paths.get(directory + File.separatorChar + filename);
}
If you create a web based application, the better solution is to check the directory exists or not then create the file if not exist. If exists, recreate again.
private File createFile(String path, String fileName) throws IOException {
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource(".").getFile() + path + fileName);
// Lets create the directory
try {
file.getParentFile().mkdir();
} catch (Exception err){
System.out.println("ERROR (Directory Create)" + err.getMessage());
}
// Lets create the file if we have credential
try {
file.createNewFile();
} catch (Exception err){
System.out.println("ERROR (File Create)" + err.getMessage());
}
return file;
}
A simple solution using Java 8
public void init(String multipartLocation) throws IOException {
File storageDirectory = new File(multipartLocation);
if (!storageDirectory.exists()) {
if (!storageDirectory.mkdir()) {
throw new IOException("Error creating directory.");
}
}
}
If you're using Java 8 or above, then Files.createDirectories() method works the best.
I want to copy files from source directory to destination. If the file already exists in the destination directory, then append the new file to be copied with its timestamp so that there is no overwrite. How do I check for duplicates and append timestamp to the new file name? Please help!
public static void copyFolder(File src, File dest)
throws IOException{
//list all the directory contents
String files[] = src.list();
for (String file : files) {
//construct the src and dest file structure
File srcFile = new File(src, file);
File destFile = new File(dest, file);
//recursive copy
copyFolder(srcFile,destFile);
}
}else{
//if file, then copy it
//Use bytes stream to support all file types
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
//copy the file content in bytes
while ((length = in.read(buffer)) > 0){
out.write(buffer, 0, length);
}
in.close();
out.close();
System.out.println("File copied from " + src + " to " + dest);
}
}
//construct the src and dest file structure
File srcFile = new File(src, file);
File destFile = new File(dest, file);
while (destFile.exists()) {
destFile = new File(dest, file + '-' + Instant.now());
}
In one case the destination file got named test-file.txt-2018-03-14T11:05:21.103706Z. The time given is in UTC. In any case you will end up with a name of file that doesn’t already exist (if the loop terminates, but I have a hard time seeing the scenario where it doesn’t).
You may want to append the timestamp only to plain files and reuse existing folders (directories), I don’t know your requirements here. And you may want to append the timestamp before the extension if there is one (to get test-file-2018-03-14T11:05:21.103706Z.txt instead). I trust you to make the necessary modifications.
You can check if the file exists using File.exist() method, if exists, you can open the file in the append mode
The code is something like this
File f = new File(oldName);
if(f.exists() && !f.isDirectory()) {
long currentTime=System.currentTimeMillis();
String newName=oldName+currentTime;
// do the copy
}
I have a question about this code I found on Android saving file to external storage
Before rushing to down vote, I'm asking this here because I'm not allowed to comment on answered questions.
private void saveImageToExternalStorage(Bitmap finalBitmap) {
String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
File myDir = new File(root + "/saved_images");
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Image-" + n + ".jpg";
//////////////////////////////////////////////////////////////////////////////////
File file = new File(myDir, fname);
if (file.exists()) // why check if it exists and delete file??????????
file.delete();
try {
FileOutputStream out = new FileOutputStream(file); // how is it being used if it is deleted???
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
}
catch (Exception e) {
e.printStackTrace();
}
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
}
my question is about the
if (file.exists())
isn't this always executed after the statement above is executed?
also why delete it after creating it, Does the statement only delete the contents and not the actual file. I read the Java doc's but it didn't clarify this for me.
thank you.
isn't this always executed after the statement above is executed?
Well, yes.
also why delete it after creating it
new File(...) does not create a file on disk. It creates a File object in the Java programming language.
Does the statement only delete the contents and not the actual file
delete() deletes the file.
I read the Java doc's but it didn't clarify this for me.
Quoting the documentation: "The actual file referenced by a File may or may not exist. It may also, despite the name File, be a directory or other non-regular file."
I'm saving an uploaded file as below:
UploadItem item = event.getUploadItem();
File dir = new File("D:/FileUpload");
if (!dir.exists()) {
dir.mkdir();
}
File bfile = new File("D:/FileUpload" + "/" + item.getFileName());
OutputStream outStream = new FileOutputStream(bfile);
outStream.write(item.getData());
outStream.close();
But my question is when upload once file same old file in folder D:/FileUpload. In above function it will delete old file. Example first time, i upload file : test.doc (old file). Then i upload another file with same name : test.doc (new file). At folder FileUpload will has one file is test.doc (new file). I want function will process similar in window OS is : new file will be test (2).doc. How can i process it ? And all cases : D:/FileUpload have many file : test.doc, test (1).doc, test (2).doc, test (a).doc,...... I think we just check with format ....(int).doc. That new file will be :
test (3).doc (ignore test(a).doc)
Maybe you're looking for something like this? I list the files in your directory, compare the names of each to the name of your file. If the names match, increment a count. Then, when you come to create your file, include the count in its name.
UploadItem item = event.getUploadItem();
File dir = new File("D:/FileUpload");
if (!dir.exists()) {
dir.mkdir();
}
String [] files = dir.list();
int count = 0;
for(String file : files) {
if (file.startsWith(item.getFileName()) {
count++;
}
}
File bfile = new File("D:/FileUpload" + "/" + item.getFileName() + "(" + count + ")");
OutputStream outStream = new FileOutputStream(bfile);
outStream.write(item.getData());
outStream.close();