10 August 2014, 08:59 | #1 |
XoXo/Tasko Developer
Join Date: Dec 2013
Location: Munich
Age: 48
Posts: 450
|
Easy way to copy a file?
Hi,
I noticed I can "copy" a file from one Dir to another by using Rename(), when both Dirs are on the same Volume. If they are not, I think I must use Open() Read()/Write() and Close(). And I must read and write the file in portions as the whole file might not fit into memory. But isn't there an easier method to copy a file from one volume to another? greets, A |
10 August 2014, 10:10 | #2 |
Registered User
Join Date: Jan 2014
Location: BO/Italy
Posts: 711
|
I think that you can simply use the command "copy"
Supposing you are in DH0: copy myfile DH1:Mydir/ You can omit the name of the "new" file if you want to keep the same or specify a new name if you want to change it when copying it. Please, correct me if I am wrong... |
10 August 2014, 10:14 | #3 |
XoXo/Tasko Developer
Join Date: Dec 2013
Location: Munich
Age: 48
Posts: 450
|
If you did not mean that, I wanted to have a solution to do copying a file from my program side. But it's a good idea to just execute() the copy command in my program.
|
10 August 2014, 11:05 | #4 |
Registered User
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
|
Why use execute()? Your original approach in the first post is correct. (What language are you programming in?)
Also, Rename() is more like a "move" than "copy". |
10 August 2014, 14:02 | #5 |
Registered User
Join Date: Jan 2014
Location: BO/Italy
Posts: 711
|
|
10 August 2014, 19:46 | #6 |
Registered User
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
|
Well, I was bored...so here is a C implementation.
if return value >=0 then no errors occured. (returns the bytes copied on normal execution) Otherwise, returns the errors in the defines. Note: lightly tested (on KS3.1 and on KS1.3), seems to work though. Code:
#include <exec/types.h> #include <dos/dos.h> #include <proto/exec.h> #include <proto/dos.h> #define FILECOPY_DEFAULT_BUFFERSIZE (32768) #define FILECOPY_SOURCE_FILE_ERROR (-1) #define FILECOPY_DESTINATION_FILE_ERROR (-2) #define FILECOPY_BUFFER_MEMORY_ERROR (-3) #define FILECOPY_READ_WRITE_ERROR (-4) LONG FileCopy(STRPTR from, STRPTR to) { LONG readBytes, writtenBytes; LONG totalBytes = 0; BPTR fromBPTR, toBPTR; void *buffer; LONG buflen = FILECOPY_DEFAULT_BUFFERSIZE; fromBPTR = Open(from, MODE_OLDFILE); if (!fromBPTR) { //PrintFault(IoErr(),"Open()"); //needs >=KS2.0 return FILECOPY_SOURCE_FILE_ERROR; } toBPTR = Open(to, MODE_NEWFILE); // !!!no overwrite check!!! if (!toBPTR) { //PrintFault(IoErr(),"Open2()"); //needs >=KS2.0 Close(fromBPTR); return FILECOPY_DESTINATION_FILE_ERROR; } while (!(buffer = AllocMem(buflen, MEMF_ANY))) { buflen >>= 1; if (buflen < 1024) { //if there not even a Kb free, shut it down, return error. Close(fromBPTR); Close(toBPTR); return FILECOPY_BUFFER_MEMORY_ERROR; } } while ((readBytes = Read(fromBPTR, buffer, buflen)) > 0) { writtenBytes = Write(toBPTR, buffer, readBytes); if (writtenBytes == -1 || writtenBytes != readBytes) { //PrintFault(IoErr(),"Write()"); //needs >=KS2.0 break; } totalBytes += writtenBytes; } Close(fromBPTR); Close(toBPTR); FreeMem(buffer, buflen); if (readBytes) { DeleteFile(to); //Delete the destination file on read/write error return FILECOPY_READ_WRITE_ERROR; } return totalBytes; } Last edited by alkis; 10 August 2014 at 19:51. Reason: Mention KS1.3 combartibility |
11 August 2014, 13:40 | #7 |
XoXo/Tasko Developer
Join Date: Dec 2013
Location: Munich
Age: 48
Posts: 450
|
The Rename() DOS library function is good for moving files, however it does not work across different volumes. I hoped that there was a single library function for copying a file somehow (which I could also use for moving a file with one Delete() added).
I am coding in 68k-ASM. The source is now exactly what I need (I can 'compile' it in my mind ). It's a great idea to catch a buffer something like as large as possible and to use the returns of Read() and Write() to handle errors and when the last portion of the file that is shorter than the buffer. The code works perfectly without finding out the actual filesize. I can easily turn the function you wrote into a "move" when I need that. How would you handle a progress bar? Check the filesize first, divide it by buffer length and set the result as max (for the bar)? But how handling the last portion? Round up the result of the division (ceil())? The bar may jump from one pos. to the next, but not grow too far or too few in total. Where in your code would you call the current setting of the progress bar? Thanks. |
11 August 2014, 14:15 | #8 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Variable "totalBytes" is increased by the amount of bytes written successfully. You could use that in relation to total file size.
No need to divide by bufferlen or any kind of rounding Last portion will be shown correctly by default. And i would call the function for progress bar there too. |
11 August 2014, 15:02 | #9 |
XoXo/Tasko Developer
Join Date: Dec 2013
Location: Munich
Age: 48
Posts: 450
|
Ah, I see. Thanks.
|
11 August 2014, 19:52 | #10 |
Registered User
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
|
Hmmm, you need something like that to get the size prior the actual copying if you want to feed a progress bar. You can call it right before the while(read/write) loop on the source filename. (it will probably fail on destination filename and also is pointless )
Note: if something fails returns 0, so you may want to guard against that. Code:
LONG GetFileSize(STRPTR filename) { __aligned struct FileInfoBlock fib; // this MUST be alligned on longword LONG ret=0; BPTR lockFrom; if (lockFrom = Lock(filename,ACCESS_READ)) { if (Examine(lockFrom,&fib)) { ret=fib.fib_Size; } UnLock(lockFrom); } return ret; } |
11 August 2014, 20:00 | #11 |
XoXo/Tasko Developer
Join Date: Dec 2013
Location: Munich
Age: 48
Posts: 450
|
Another way to get the filesize is to seek for it, just after the file has been opened: Seek once to it's end and then back to start. Result will be the size of the file. Then start reading.
|
11 August 2014, 20:31 | #12 |
XoXo/Tasko Developer
Join Date: Dec 2013
Location: Munich
Age: 48
Posts: 450
|
Here is the Seek() Variant to get filesize w/o need of a fileinfoblock:
Code:
move.l cf_inhandle(a7),d1 moveq #0,d2 move.l #OFFSET_END,d3 jsr _LVOSeek(a6) ; The result here can only be negativ, or zero, ; as we started at pos 0. And 0 is exactly what ; we need in d2 here, as offset for the second seek. move.l d0,d2 bmi .ioerr ; As Seek() ; returns the old pos in the file, the whole ; filesize is returned when we seek from the end. move.l cf_inhandle(a7),d1 move.l #OFFSET_START,d3 jsr _LVOSeek(a6) move.l d0,cf_filesize(a7) bmi .ioerr Last edited by AGS; 11 August 2014 at 20:37. |
11 August 2014, 20:39 | #13 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,514
|
Better use Examine() to get file size because seek method is really slow if file is large and filesystem is OFS or FFS.
|
11 August 2014, 20:43 | #14 |
XoXo/Tasko Developer
Join Date: Dec 2013
Location: Munich
Age: 48
Posts: 450
|
Good to know!
|
11 August 2014, 20:54 | #15 |
Computer Nerd
Join Date: Sep 2007
Location: Rotterdam/Netherlands
Age: 47
Posts: 3,761
|
Use ExamineFH() to get the file info block from a file handle. That way you don't have to Lock() the file first. Allocate space for the file info block with AllocDosObject().
|
11 August 2014, 20:55 | #16 |
XoXo/Tasko Developer
Join Date: Dec 2013
Location: Munich
Age: 48
Posts: 450
|
AH, very good!
|
11 August 2014, 20:58 | #17 |
Computer Nerd
Join Date: Sep 2007
Location: Rotterdam/Netherlands
Age: 47
Posts: 3,761
|
Forgot to add that you should free the memory allocated with AllocDosObject() with FreeDosObject().
|
11 August 2014, 21:01 | #18 |
XoXo/Tasko Developer
Join Date: Dec 2013
Location: Munich
Age: 48
Posts: 450
|
There is written something that the filesize returned does not reflect the realsize when someone is active in it ...
|
11 August 2014, 21:05 | #19 |
Registered User
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
|
ExamineFH() kills 1.3 combartibility (don't know if that's an issue, just saying)
Also, no need to AllocDosObject() for two reasons: - Alligning on longword is enough - KS1.3 combartibility ;-) |
11 August 2014, 21:06 | #20 |
XoXo/Tasko Developer
Join Date: Dec 2013
Location: Munich
Age: 48
Posts: 450
|
May I reuse an allocated fib for multiple files?
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Copy file from PC filesystem to WinUAE harddisk | Raizor | support.WinUAE | 2 | 10 January 2011 20:44 |
Copy CF card file to ram:, insert other CF card, copy over? | Photon | support.Hardware | 16 | 21 July 2009 22:05 |
Very slow file copy? | DDNI | support.WinUAE | 4 | 16 March 2009 22:16 |
Copy file containing control codes to printer? | Photon | support.Apps | 1 | 10 December 2006 02:36 |
Problems with massive file copy & JIT | jotd | support.WinUAE | 1 | 15 November 2006 19:16 |
|
|