I need to download some files via ftp from an old AS/400 server. My code looks more or less like:
FtpWebRequest _request = (FtpWebRequest)WebRequest.Create("ftp://ftpaddress/FOO.CSV");
_request.Credentials = new NetworkCredential(_ftpUsername, _ftpPassword);
_request.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse response = (FtpWebResponse)_request.GetResponse();
However, an exception is being thrown with the message:
501 Character (/) not allowed in object name.
I'm guessing the AS400 uses a different path separator than / but I can't figure out how to phrase the uri in a way (1) FtpWebRequest accepts and (2) the AS400 understands.
Anyone else bumped into this?
According to this page, fwd slash is the path separator character:
The forward slash is the separator character for paths sent to the FTP server.
A similar conversation over at Microsoft's forums (2005 era) indicates it's a bug in FtpWebRequest:
Currently FtpWebRequest does not support quote and I cannot think of a way you'll be able to overide the method without exposing our code Mariya Atanasova [NCL]MSFT, Moderator, Nov 2005
Try updating to the most recent versions or try a different library; the MS forum thread has several.
I've had this message often in the past, and it meant that I forgot to change the name format.
There are two name formats possible when doing FTP with an AS400, and it can be changed with the FTP command NAMEFMT:
0 is for the library system files (library\filename.member)
1 is for the files in the IFS, where a CSV file would be
By default, it is set to 0.
Change it to 1 and it should work. However I'm not sure how it can be changed with a FtpWebRequest.
To make life a little bit easier, the FTP server decides what NameFormat you want to use, based on your first command. If you start with "cd /home", then the FTP server does automatically set NAMEFMT to 1 for you.
Indeed, you can change this manually during your session with the remote FTP command NAMEFMT. Please, notice that you don't need the (old) iSeries way. You can address EVERY object on the iSeries with NAMEFMT 1. For example, "get /QSYS.LIB/MYLIBRARY.LIB/MYFILE.FILE/MYMEMBER.MBR" will do the trick for any iSeries database table. Even for multimember files!
This is an aggregate answer from the ones previously provided, but I was able to get this working by using the following structure:
ftp://[HostName]/%2F/[directory]/[subdirectory]/[filename].csv
The '%2F' was required and serves as a separator between the host name and the path.
Related
I'm currently working on a little program for backing up your Bitcoin Core wallet. I am using BitcoinLib v1.15.0 in C#.
IBitcoinService bitcoinService = new BitcoinService("http://127.0.0.1:8332", "test", "test", "", 60);
bitcoinService.BackupWallet("C:\\Users\\dominik\\OneDrive\\Desktop\\backup");
When I run this code I get following error message Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).
I am a bit confused, because the BitcoinService.backupwallet(string destination) function has only one input parameter which I assume describes the path where it should generate the backup file (or at least that's the way this command works in Bitcoin Core's terminal).
Is there anyone with experience with BitcoinLib or similar problem. I am open to any suggestions.
The error is related to multiple wallets open at once in Bitcoin Core.
It worked after I've added /wallet/<wallet_name> to the RPC URL
This is just a guess at this stage but you have not specified the file extension in this path "C:\Users\dominik\OneDrive\Desktop\backup" so it does not know exactly which file to look for. In other words the filename is incorrect as it is missing the extension of ".something". Otherwise something else is wrong with your path because maybe it has to have /wallet/ then the uri path but your path does not have that. Please let me know how you go.
If you willing to backup a wallet:
Make sure your bitcoin node up and running
Check used username & password (config file on Windows placed at %APPDATA%\bitcoin\bitcoin.conf)
Use a path with slashes instead of backslashes, ie. c:/users/username/backup/bitcoin/ or c:/users/username/backup/bitcoin/wallet_backup.dat or ../backup/wallet_backup.dat
For me the error was the bitcoin config file.
Check the wallet name property wallet=<your_wallet_name> at bitcoin.conf is correct.
I got exactly the same error message, only because too much wallets where loaded in the same time.
With the latest client (Bitcoin Core 23.0), this can be solved using these API calls (in a kind of Python pseudo-code):
wallets_list = listwallets()
for w in wallets_list:
unloadwallet(w)
loadwallet("my_wallet")
I have a question regarding the ftp library from C#. I need to download 9000 txt files from a ftp server. Station.ToUpper() is the file name, so for every file I need a new ftp connection. For one file it takes around one second. The txt files contain two lines. So for all files it takes around one and a half hour. Is there a better / faster solution?
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpAddress + station.ToUpper());
//request.UsePassive = false;
request.Method = WebRequestMethods.Ftp.DownloadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential("anonymous", "janeDoe#contoso.com");
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
There's not much you're doing wrong in this code, except for the fact you're not calling Dispose() on your streams or response objects. Do that first to make sure you're not somehow running out of resources on the client or something.
Other than that, you don't have too many options here, and a lot depends upon what you can do on the server side.
First, you could try to use threading to download a bunch of files at once. You'll need to experiment with how this affects your throughput. It will probably scale linearly for a while, then fall off. If you open up too many connections, you could anger the maintainer of the server, or it could start denying you connections. Be conservative.
Optimally, the files would be zipped (.ZIP or .TGZ) on the server. This will likely not be an option if you don't have more control over the process.
Use the MGET command to avoid re-establishing a connection each time. The System.Net client does not support MGET, so you would have to use a third party library or script ftp.exe. Regardless of the client you choose, the FTP log would look like the following:
USER anonymous
PASS janeDoe#contoso.com
CWD path/to/file
// to get 3 named files
MGET file1.txt file2.txt file3.txt
// or to get all files matching a pattern
MGET *.txt
The file transfers will use the same control session, avoiding login and other network overhead.
One library which could be of interest is FTPLib, which avoids tearing down the channel on each command. Be careful, however, as FTPLib is based on wininet which is not allowable for use in an NT Service.
I would also take a look at LumiSoft, an open source project with a friendly license, and DotNetFtpLib, though I have used neither and cannot speak to their stability or featureset. On the scripting side, take a look at "Using FTP Batch Scripts".
I'm creating a program which downloads files off various types of servers, such as network paths or HTTP servers, based upon criteria. So far I have it working based upon a regex, but I'd also like it to find files newer (last accessed, modified or created) than a given date. This is easy in the network path type because I can access the FileInfo for that file, but all I have in my FTP server is a 'line' string which obviously just holds the file name.
Is it easy/possible to access the last modified/accesesed/created dates for a file on an FTP server in C#?
Unfortunately FTP provides only limited information about the remote file. With default LIST command you get OS-specific response where one date is usually present (this is usually last modification time). With MLST/MLSD extension commands you get machine-parsable response string but also with just one time.
The exact way to get the date depends on what component or class you use to access the FTP server.
If you need to get more than one date (eg. date of creation and last access), and you can go SFTP route, I'd recommend using SFTP instead.
You could use a third party library such as edtFTP to connect to the FTP server and inspect the last modified/created (not sure if you can get the the last accessed timestamp) timestamps. Its quite an easy library to use:
We have a C# .Net client application that sends some commands via REST over HTTP. The server is on a Linux machine written in Perl.
These commands contain file paths located on the server that can be entered by the user. Since the users are on windows, we'd like for them to be case-insensitive, but this is giving us some issues in locating the files server side.
How can we get the correct casing?
We have 2 possible solutions:
Use a winapi call on the client to fix the path to be properly cased. (These files are visible by a shared folder on the clients computer)
Use some perl code on the server to locate a file with a case-insensitive path as input
Any suggestions? We would like this to work on all client machines that are Windows XP SP2 and higher.
UPDATE: We decided it should be fixed client side, on the rare case that there is a case mismatch.
We run this if we get a "file not found" error on the directory of the file. Someone would have to modify this to work for files as well, but in our case the filename could never be wrong (I'd rather not explain why):
string FixDirectory(string fullpath)
{
return fullpath
.Split(Path.DirectorySeparatorChar)
.Skip(1)
.Select(path =>
{
string[] split = fullpath.Split(new string[] { path }, StringSplitOptions.None);
string tempDir = split[0];
string[] dirs = Directory.GetDirectories(tempDir, path);
fullpath = fullpath.Replace(Path.Combine(tempDir, path), dirs[0]);
return fullpath;
})
.Last();
}
Your first proposal makes sense -- if the client can see the file, then use an API call on the client to get the real filename (with the correct case) before submitting that data to the server. The user shouldn't have to manually type in a filename at all - use the standard "Browse..." widget to bring up a dialog box that allows the user to find the file in his filesystem.
Using a case-insensitive file search on the case-sensitive server should only be a last resort. As you mentioned in your follow-up comment, there are various edge cases that are annoying to account for, so it would be best to avoid this scenario entirely.
This sounds like a job for the server. If you give a case sensitive server a case insensitive string, it can more easily find the desired file than the client can.
Can you normalize the character cases on your server? For example, force all directory and file names to be lowercase.
If so, then your server process would easily convert requests for My/FILE.XLS and my/file.XLS to my/file.xls.
Normalization avoids a lot of complicated search logic and it prevents collisions between similar file names.
I need to monitor a certain file on FTP, once it had been updated, I need to fetch it from FTP. but how to identify whether it's updated or not is a problem.
Does Anybody have any experience on this?
You need to send a LIST command. You'll need to parse the results manually using regex, since there is no standard format for the return result.
File modification data and time can be also obtained using a MLST or a MDTM command. Both ones are extensions of FTP protocol (not guaranteed on all servers), but at least some of them is supported by most servers. These commands return standardized format, it has not to be parsed like results of LIST command.
See the more details in this article.