I am trying to copy some Files to SD Card and then delete them . But many times the files are not getting copied and only getting Deleted.
And also many times the FileInputStreamis null where as i am checking if the file which has to be transferred exists or not and also if it is writable or not.
This is the Code i am using to move a file
public static void move(final File remove,final DocumentFile move_to_folder) {
final String mime = MimeTypes.getMimeType(remove);
final DocumentFile move = move_to_folder.createFile(mime, remove.getName());
try {
inStream = new FileInputStream(remove);
outStream =
con.getApplicationContext().getContentResolver().openOutputStream(move.getUri());
final byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(inStream!=null)
{
inStream.close();
}
if(outStream!=null)
{
outStream.close();
}
delete(remove);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I am transferring many files at a time so i am using this code inside an Async Task .
Any help would be really Grateful.
If you have an exception, the remove gets deleted without consideration
Consider adding a boolean flag to prevent this
e.g.
before the try block add
boolean canDelete = true;
If you have an exception set
canDelete = false;
and then in the finally check this boolean
if (canDelete)
delete(remove);
Related
I am trying to make a file manager app in Android.
I want to provide the user with an option to move their files. So first I am copying the Files then I am deleting the file if there is no error.
This is the code I am using to copy the files
public static boolean copy(File copy, String directory, Context con) {
static FileInputStream inStream = null;
static OutputStream outStream = null;
DocumentFile dir = getDocumentFileIfAllowedToWrite(new File(directory), con);
String mime = "";
DocumentFile copy1 = dir.createFile(mime, copy.getName());
try {
inStream = new FileInputStream(copy);
outStream = con.getContentResolver().openOutputStream(copy1.getUri());
byte[] buffer = new byte[16384];
int bytesRead;
while ((bytesRead = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inStream.close();
outStream.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
But in one of my devices the files are simply getting deleted without copying.
So my thought is that I will check the length of the file by SourceFile.length() and the length of the DestinationFile.length() if both are same or not. If both are same then I will delete the SourceFile.
Is the most effective way to check it without checking the MD5 of an File? Also what are the chances that the file transfer is incomplete/corrupted and still the length is same?
I am working in a feature for an LMS to download a bunch of selected files and folders in a zip on-the-fly. I have used ZipOutputStream to prevent OutOfMemory issues.
The feature works nice, but we have done a stress test and when several users are downloading zips at the same time (lets say 10 users zipping about 100 MB each one), 4 out of 4 CPUs reach 100% of load until the zips are created. Our system admins think that this is not acceptable.
I wonder if there is some mechanism to do ZipOutputStream use less system resources, no matter if it takes more time to finish.
My current code:
protected void compressResource(ZipOutputStream zipOut, String collectionId, String rootFolderName, String resourceId) throws Exception
{
if (ContentHostingService.isCollection(resourceId))
{
try
{
ContentCollection collection = ContentHostingService.getCollection(resourceId);
List<String> children = collection.getMembers();
if(children != null)
{
for(int i = children.size() - 1; i >= 0; i--)
{
String child = children.get(i);
compressResource(zipOut,collectionId,rootFolderName,child);
}
}
}
catch (PermissionException e)
{
//Ignore
}
}
else
{
try
{
ContentResource resource = ContentHostingService.getResource(resourceId);
String displayName = isolateName(resource.getId());
displayName = escapeInvalidCharsEntry(displayName);
InputStream content = resource.streamContent();
byte data[] = new byte[1024 * 10];
BufferedInputStream bContent = null;
try
{
bContent = new BufferedInputStream(content, data.length);
String entryName = (resource.getContainingCollection().getId() + displayName);
entryName=entryName.replace(collectionId,rootFolderName+"/");
entryName = escapeInvalidCharsEntry(entryName);
ZipEntry resourceEntry = new ZipEntry(entryName);
zipOut.putNextEntry(resourceEntry); //A duplicate entry throw ZipException here.
int bCount = -1;
while ((bCount = bContent.read(data, 0, data.length)) != -1)
{
zipOut.write(data, 0, bCount);
}
try
{
zipOut.closeEntry();
}
catch (IOException ioException)
{
logger.error("IOException when closing zip file entry",ioException);
}
}
catch (IllegalArgumentException iException)
{
logger.error("IllegalArgumentException while creating zip file",iException);
}
catch (java.util.zip.ZipException e)
{
//Duplicate entry: ignore and continue.
try
{
zipOut.closeEntry();
}
catch (IOException ioException)
{
logger.error("IOException when closing zip file entry",ioException);
}
}
finally
{
if (bContent != null)
{
try
{
bContent.close();
}
catch (IOException ioException)
{
logger.error("IOException when closing zip file",ioException);
}
}
}
}
catch (PermissionException e)
{
//Ignore
}
}
}
Thanks in advance.
I have solved it with a simple hack told by #shmosel.
private static Semaphore mySemaphore= new Semaphore(ServerConfigurationService.getInt("content.zip.download.maxconcurrentdownloads",5),true);
(...)
ZipOutputStream zipOut = null;
try
{
mySemaphore.acquire();
ContentCollection collection = ContentHostingService.getCollection(collectionId);
(...)
zipOut.flush();
zipOut.close();
mySemaphore.release();
(...)
This is working in my test server. But if anybody has any objection or any extra advice, I will be happy to hear.
Let's say I have an URL, like something.domain/myfile.txt then I want to save this file, with that "Save File" dialog.
I tried my best to do it, but everytime I save the file using the dialog the file is not there.
An example or somewhere I can find information on this would help a lot!
URL website = null;
try {
website = new URL(<insert url here>);
} catch (MalformedURLException e) {
e.printStackTrace();
}
ReadableByteChannel rbc = null;
try {
rbc = Channels.newChannel(website.openStream());
} catch (IOException e2) {
e2.printStackTrace();
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File("minecraft.jar"));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try {
fos.getChannel().transferFrom(rbc, 0, 1 << 24);
} catch (IOException e) {
e.printStackTrace();
}
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showSaveDialog(fileChooser) == JFileChooser.APPROVE_OPTION) {
File dir = fileChooser.getCurrentDirectory();
dir.mkdir();
//After this point is where I need help.
I trust that this is what you're looking for:
if (fileChooser.showSaveDialog(fileChooser) == JFileChooser.APPROVE_OPTION)
{
File file = fileChooser.getSelectedFile();
// whatever you want to do with the file
System.out.println("The file is "+file.getAbsolutePath());
// fos = new FileOutputStream(file) ...
}
Did you notice that in your code you are trying to save/download the file before giving the user the option to chose the destination?
I would split the code into three different operations:
A method in charge of transferring the bytes from the InputStream (the web) to the OutputStream (the file).
a method to show the user a dialog so he can chose where to store the file.
the method that completes the whole task: choose a file and transfer the bytes from the web to it.
1) Would be something like this (you don't need to use the NIO API to implement it):
public void transfer(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[2048];
int bytesRead;
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
}
2) would be something very similar to what Dukeling has already stated:
public File chooseFile() {
File result = null;
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showSaveDialog(fileChooser) == JFileChooser.APPROVE_OPTION) {
result = fileChooser.getSelectedFile();
}
return result;
}
3) then, combining these two operations together is really simple:
public void saveFileFromWeb(URL url) {
File file = chooseFile(); // 1. Choose the destination file
if (file != null) {
// 2. Create parent folder structure
File folder = file.getParentFile();
if (!folder.exist()) {
folder.mkdirs();
}
InputStream in = null;
OutputStream out = null;
try {
// 3. Initialise streams
in = url.openStream();
out = new FileOuputStream(file);
// 4. Transfer data
transfer(in, out);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 5. close streams
if (in != null) {
try {
in.close();
} catch (IOException e) { /* ignore */ }
}
if (out != null) {
try {
out.close();
} catch (IOException e) { /* ignore */ }
}
}
}
NOTE: 1) and 2) could be private methods. Of course you could do this is just one single operation but splitting it would give you an overview of the different steps to perform.
NOTE 2: I simplified the exception handling part
well my question is really simple, is about an unexpected behavior (or at least is unexpected to me) while I try to zip a directory, I have the following methods that I've created on my own (I'm quite aware that I'm not handling exceptions and all that stuff, It is because (by now) I'm just doing this to learn how to do it so stability "is not really important"), here is the code:
public static void zipDirectory(File srcDirectory, File zipFile) throws IllegalArgumentException {
if (!srcDirectory.isDirectory()) {
throw new IllegalArgumentException("The first parameter (srcDirectory) MUST be a directory.");
}
int bytesRead;
byte[] dataRead = new byte[1000];
BufferedInputStream in = null;
ZipOutputStream zOut;
try {
zOut = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
for (File f : srcDirectory.listFiles()) {
if (f.isDirectory()) {
FileUtilities.zipInnerDirectory(f,zOut);
}else {
in = new BufferedInputStream(new FileInputStream(f.getAbsolutePath()), 1000);
zOut.putNextEntry(new ZipEntry(f.getPath()));
while((bytesRead = in.read(dataRead,0,1000)) != -1) {
zOut.write(dataRead, 0, bytesRead);
}
zOut.closeEntry();
}
}
zOut.flush();
zOut.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void zipInnerDirectory(File dir, ZipOutputStream zOut) throws IllegalArgumentException {
if (!dir.isDirectory()) {
throw new IllegalArgumentException("The first parameter (srcDirectory) MUST be a directory.");
}
BufferedInputStream in = null;
int bytesRead;
byte[] dataRead = new byte[1000];
try {
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
FileUtilities.zipInnerDirectory(f,zOut);
}else {
in = new BufferedInputStream(new FileInputStream(f.getAbsolutePath()), 1000);
zOut.putNextEntry(new ZipEntry(f.getPath()));
while((bytesRead = in.read(dataRead,0,1000)) != -1) {
zOut.write(dataRead, 0, bytesRead);
}
zOut.closeEntry();
}
}
zOut.flush();
zOut.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
As I said is not my best coding so please don't judge the code (or at least don't be too strict ;) ), I know it can be so much better; ok the "unexpected behavior" is this, let's say that I have the following directory:
H:\MyDir1\MyDir2\MyDirToZip
when i send as a parameter a file created with that path (new File("H:\\MyDir1\\MyDir2\\MyDirToZip")) everything's work pretty fine the zip is created successfully, the thing is that when I open (unzip) the files inside the zip they have the next structure:
H:\MyDir1\MyDir2\MyDirToZip
when I was expecting to find inside just:
\MyDirToZip
without H: \MyDir1 \MyDir2 which are "unnecessary" (BTW they just contain one to each other in the appropriate order, i mean, the other files that are in them are not compressed, that is why I say they are unnecessary) so the question is, what I'm I doing wrong? how can I specify that I just want to zip the structure down the srcDirectory?
zOut.putNextEntry(new ZipEntry(f.getPath()));
This should be the problem. f.getPath() will return a path that's relative to some root directory (probably your current working dir), but not relative to the directory you are zipping. You need to figure out a way to get the relative path from the zip directory, possibly this will do:
new ZipEntry(f.getAbsolutePath().substring(zipDir.getAbsolutePath().length()))
or, if you want the root directory added:
new ZipEntry(zipDir.getName() + "/"
+ f.getAbsolutePath().substring(zipDir.getAbsolutePath().length()))
public static void writeFile(String theFileName, String theFilePath)
{
try {
File currentFile = new File("plugins/mcMMO/Resources/"+theFilePath+theFileName);
//System.out.println(theFileName);
#SuppressWarnings("static-access")
JarFile jar = new JarFile(plugin.mcmmo);
JarEntry entry = jar.getJarEntry("resources/"+theFileName);
InputStream is = jar.getInputStream(entry);
byte[] buf = new byte[(int)entry.getSize()];
is.read(buf, 0, buf.length);
FileOutputStream os = new FileOutputStream(currentFile);
os.write(buf);
os.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Alright so in my program I have various resources kept within the Jar of the program, when the program runs it has specific files passed to this function that are written to the HDD of the users computer. Everything gets written, but only the images come out 100% correct. The sound files are not so lucky.
Basically, I CANNOT get the sounds to write correctly, their file sizes are correct but they only contain a split second of audio instead of their full length audio. Am I missing something here? I seem to have done everything right, but if that was true I wouldn't be posting here.
I tried my best at googling this problem but it has failed me.
Any guess as to why this doesn't work would be AMAZING!! :)
As JarEntry extends ZipEntry, I would recommend not to rely on the ZipEntry.getSize() method as it return -1. See the doc.
Moreover, it's in general much more common to take advantage of buffering when reading a stream. In your example, you put everything inside your byte array, so I guess for big files you could end up in an OutOfMemoryError.
Here would be the code I would test:
public static void writeFile(String theFileName, String theFilePath)
{
try {
File currentFile = new File("plugins/mcMMO/Resources/"+theFilePath+theFileName);
#SuppressWarnings("static-access")
JarFile jar = new JarFile(plugin.mcmmo);
JarEntry entry = jar.getJarEntry("resources/"+theFileName);
InputStream is = jar.getInputStream(entry);
byte[] buf = new byte[2048];
int nbRead;
OutputStream os = new BufferedOutputStream(new FileOutputStream(currentFile));
while((nbRead = is.read(buf)) != -1) {
os.write(buf, 0, nbRead);
}
os.flush();
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}