English Amiga Board

English Amiga Board (https://eab.abime.net/index.php)
-   Coders. System (https://eab.abime.net/forumdisplay.php?f=113)
-   -   Easy way to copy a file? (https://eab.abime.net/showthread.php?t=74665)

AGS 10 August 2014 08:59

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

liviux76 10 August 2014 10:10

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... :)

AGS 10 August 2014 10:14

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.

alkis 10 August 2014 11:05

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".

liviux76 10 August 2014 14:02

Quote:

Originally Posted by alkis (Post 968816)
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".

As far as I know "rename" for AmigaDOS is equal to "mv" in *nix shell so it moves and don't copy.

alkis 10 August 2014 19:46

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;
}


AGS 11 August 2014 13:40

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. :D

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.

BigFan 11 August 2014 14:15

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.

AGS 11 August 2014 15:02

Ah, I see. Thanks.

alkis 11 August 2014 19:52

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;
}


AGS 11 August 2014 20:00

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.

AGS 11 August 2014 20:31

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


Toni Wilen 11 August 2014 20:39

Better use Examine() to get file size because seek method is really slow if file is large and filesystem is OFS or FFS.

AGS 11 August 2014 20:43

Good to know! :D

Thorham 11 August 2014 20:54

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().

AGS 11 August 2014 20:55

AH, very good! :D

Thorham 11 August 2014 20:58

Forgot to add that you should free the memory allocated with AllocDosObject() with FreeDosObject().

AGS 11 August 2014 21:01

There is written something that the filesize returned does not reflect the realsize when someone is active in it ...

alkis 11 August 2014 21:05

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 ;-)

AGS 11 August 2014 21:06

May I reuse an allocated fib for multiple files?


All times are GMT +2. The time now is 22:53.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.

Page generated in 0.04747 seconds with 11 queries