FileExists() and FileCopy() supporting Unicode file names

New to FreeBASIC? Post your questions here.
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

FileExists() and FileCopy() supporting Unicode file names

Postby newbieforever » Jan 20, 2019 23:02

These functions (included in file.bi) seems not to work with file names containing non-ASCII characters.

Where functions can be found which would support file names like "Сергeй.txt"?
dodicat
Posts: 5554
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FileExists() and FileCopy() supporting Unicode file names

Postby dodicat » Jan 20, 2019 23:42

The c runtime has many unicode functions.
I made up an exists here.
(I must use Poseidon ide for this)

Code: Select all



#include "crt.bi"

declare function wsystem cdecl alias "_wsystem" (byval as wstring ptr) as long  'not in crt.bi



function exists(filename as wstring) as boolean
dim as wstring * 50 r="rt+,ccs=UNICODE"'"r"
 dim as file ptr fp = _wfopen(@filename,@r)
 fclose(fp)
 return cint(fp)
 end function
 


dim as wstring * 15 w= wstr("Сергeй.txt")


wsystem("echo hello > "+w)

wsystem("echo hello there > asciname.txt")

wsystem("type " + w)

wsystem("type asciname.txt")
print
wsystem("dir "  + "/b")

print exists(w)
print exists("asciname.txt")
print exists("dummy.txt2")



sleep
 
caseih
Posts: 1317
Joined: Feb 26, 2007 5:32

Re: FileExists() and FileCopy() supporting Unicode file names

Postby caseih » Jan 21, 2019 2:11

Yes the *Microsoft* C runtime has many unicode functions out of necessity[1]. But they're definitely not part of the C standard runtime. Any function that begins with an underscore is a non-standard addition. So it works on Windows only, but it's definitely not portable to any other operating system.

The ANSI standard C runtime has zero support for unicode or unicode decoding and encoding. But on operating systems that use UTF-8 (pretty much any OS other than Windows), it doesn't really need to support unicode. That can be left to a higher level abstraction and other libraries.

[1] MS chose to use UCS-2, then later UTF-16, which meant they had to duplicate every API in their system to support 2-byte unicode characters, as well as traditional bytes.
Josep Roca
Posts: 413
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: FileExists() and FileCopy() supporting Unicode file names

Postby Josep Roca » Jan 21, 2019 6:42

> Where functions can be found which would support file names like "Сергeй.txt"?

Here: https://github.com/JoseRoca/WinFBX

From AfxWin.inc:

Code: Select all

' ========================================================================================
' Searches a directory for a file or subdirectory with a name that matches a specific name
' (or partial name if wildcards are used).
' Parameter:
' - pwszFileSpec: The directory or path, and the file name, which can include wildcard
'   characters, for example, an asterisk (*) or a question mark (?).
'   This parameter should not be NULL, an invalid string (for example, an empty string or a
'   string that is missing the terminating null character), or end in a trailing backslash (\).
'   If the string ends with a wildcard, period (.), or directory name, the user must have
'   access permissions to the root and all subdirectories on the path. To extend the limit
'   of MAX_PATH wide characters to 32,767 wide characters, prepend "\\?\" to the path.
' Return value:
'   Returns TRUE if the specified file exists or FALSE otherwise.
' Remarks:
'   Prepending the string "\\?\" does not allow access to the root directory.
'   On network shares, you can use a pwszFileSpec in the form of the following:
'   "\\server\service\*". However, you cannot use a pwszFileSpec that points to the share
'   itself; for example, "\\server\service" is not valid.
'   To examine a directory that is not a root directory, use the path to that directory,
'   without a trailing backslash. For example, an argument of "C:\Windows" returns information
'   about the directory "C:\Windows", not about a directory or file in "C:\Windows".
'   To examine the files and directories in "C:\Windows", use an pwszFileSpec of "C:\Windows\*".
'   Be aware that some other thread or process could create or delete a file with this name
'   between the time you query for the result and the time you act on the information.
'   If this is a potential concern for your application, one possible solution is to use
'   the CreateFile function with CREATE_NEW (which fails if the file exists) or OPEN_EXISTING
'   (which fails if the file does not exist).
' ========================================================================================
PRIVATE FUNCTION AfxFileExists (BYVAL pwszFileSpec AS WSTRING PTR) AS BOOLEAN
   DIM fd AS WIN32_FIND_DATAW
   IF pwszFileSpec = NULL THEN EXIT FUNCTION
   DIM hFind AS HANDLE = FindFirstFileW(pwszFileSpec, @fd)
   IF hFind = INVALID_HANDLE_VALUE THEN EXIT FUNCTION
   FindClose hFind
   ' // Make sure that it is not a directory or a temporary file
   IF (fd.dwFileAttributes AND FILE_ATTRIBUTE_DIRECTORY) <> FILE_ATTRIBUTE_DIRECTORY AND _
      (fd.dwFileAttributes AND FILE_ATTRIBUTE_TEMPORARY) <> FILE_ATTRIBUTE_TEMPORARY THEN
      FUNCTION = TRUE
   END IF
END FUNCTION
' ========================================================================================


Code: Select all

' ========================================================================================
' Copies an existing file to a new file.
' - lpExistingFileName : The name of an existing file.
'   To extend the limit of MAX_PATH characters to 32,767 wide characters prepend "\?" to the path.
'   If lpExistingFileName does not exist, CopyFile fails, and GetLastError returns ERROR_FILE_NOT_FOUND.
' - lpNewFileName : The name of the new file.
'   To extend the limit of MAX_PATH characters to 32,767 wide characters prepend "\?" to the path.
' - bFailIfExists
'   If this parameter is TRUE and the new file specified by lpNewFileName already exists, the
'   function fails. If this parameter is FALSE and the new file already exists, the function
'   overwrites the existing file and succeeds.
' Return value:
'   If the function succeeds, the return value is TRUE.
'   If the function fails, the return value is FALSE. To get extended error information, call GetLastError.
' ========================================================================================
PRIVATE FUNCTION AfxCopyFile (BYVAL lpExistingFileName AS LPCWSTR, BYVAL lpNewFileName AS LPCWSTR, BYVAL bFailIfExists AS BOOLEAN = FALSE) AS BOOLEAN
   RETURN CopyFileW(lpExistingFileName, lpNewFileName, bFailIfExists)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Unicode replacement for Free Basic's FileCopy.
' Returns 0 on success, or 1 if an error occurred.
' ========================================================================================
PRIVATE FUNCTION AfxFilecopy (BYVAL lpExistingFileName AS LPCWSTR, BYVAL lpNewFileName AS LPCWSTR) AS LONG
   DIM nRet AS LONG = IIF(CopyFileW(lpExistingFileName, lpNewFileName, FALSE) = 0, 1, 0)
   RETURN nRet
END FUNCTION
' ========================================================================================
dodicat
Posts: 5554
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FileExists() and FileCopy() supporting Unicode file names

Postby dodicat » Jan 21, 2019 10:54

caseih
It seems much easier in Linux with shell

Code: Select all

   shell "if [ -f Сергeй.txt ]; then echo exists; fi"
shell "if [ ! -f Сергeй.txt ]; then echo does not exist; fi"

also this works straight off

Code: Select all

   dim as wstring * 15 w= wstr("Сергeй.txt")
print w

shell("echo hello > "+ w)


Thanks Josep Roca, I shall test later.
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

Re: FileExists() and FileCopy() supporting Unicode file names

Postby newbieforever » Jan 21, 2019 17:57

OK, I will test later too.

An additional question:

With

Code: Select all

#Define unicode
#Include once "windows.bi"
#Include once "win/shellapi.bi"

Unicode-supporting functions LoadFile() and SaveFile() (and ShellExecuteW()) are provided. As I have now discovered, also DeleteFile() is included. Are there othere file-related functions in this libraries? (Copy, Rename?)
dodicat
Posts: 5554
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FileExists() and FileCopy() supporting Unicode file names

Postby dodicat » Jan 22, 2019 1:48

Here's a little helper for snooping around windows.

Code: Select all

 

#include "windows.bi"
#Include "win/shellapi.bi"


Call this file zzwindows.bas, put in your working folder.
compile with the -pp switch.
(fbc -pp zzwindows.bas)
This will give you zzwindows.pp.bas, which is the one you want to easily browse because it rests at the bottom of your working folder.
You have 28101 lines of windows constants/declarations e.t.c.
dodicat
Posts: 5554
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FileExists() and FileCopy() supporting Unicode file names

Postby dodicat » Jan 22, 2019 14:23

Here a file save and load (c) and the copy from windows.

Code: Select all


#include "crt.bi"

extern "windows"
declare function CopyFileW(byval lpExistingFileName as wstring ptr, byval lpNewFileName as wstring ptr, byval bFailIfExists as BOOLean) as BOOLean
end extern

const size=5000

sub save(filename as wstring,content as wstring)
    dim as wstring * 20 w="wt+,ccs=utf-8"
   var fp = _wfopen(@filename,@w)
   if fp then fputws(@content,fp) else print "could not save "+filename
   fclose(fp)
end sub


sub load(filename as wstring,content as wstring)
     dim as wstring * 20 r="rt+,ccs=utf-8"
     dim as wstring * size t
   dim as file ptr fp = _wfopen(@filename,@r)
   if fp=0 then print "Unable to load ";filename:sleep:exit sub
   while 1
    if (fgetws (@t,size,fp)= 0)then exit while
    content+=t
wend
fclose(fp)
end sub

dim as wstring * 50 w= wstr("СергeйСергeй.txt")

dim as wstring * 100 message=wstr("hello from СергeйСергeй.txt, but I am in another file now")

save(w,message)


dim as boolean b =false 'creates a new file if false
print "copied "; copyfileW(w,"a newfile.txt",b)
print "Folder contents:"
print
shell "dir /b"
print
dim as wstring * 1000 content

load("a newfile.txt",content)
print content
sleep


   

Return to “Beginners”

Who is online

Users browsing this forum: Exabot [Bot], Majestic-12 [Bot] and 3 guests