Search code examples
javajcifsapache-commons-vfs

How can I create and write to a CSV file in a remote, username and password protected location?


I have to create and fill a CSV file with some data, and then place it into the username and password protected remote location on a client's computer. I'm using apache-commons CSVPrinter to write the file. A scheduled job writes the file, but I can't seem to pass the authentication process.

UserAuthenticator auth = new StaticUserAuthenticator(domain, userName, password);
FileSystemOptions opts = new FileSystemOptions();

DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts, auth);
FileObject fo = VFS.getManager().resolveFile(exportLocation + fileName, opts);

BufferedWriter writer = Files.newBufferedWriter(Paths.get(fo.getURL().getPath()), StandardCharsets.UTF_8);

CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT.withDelimiter(';'));

I'm getting a java.nio.file.AccessDeniedException with the upper code. Can anyone advise me how to approach the issue, and tell me what I am doing wrong?

**************************************************** EDIT ********************************************************

I have updated the code to:

UserAuthenticator auth = new StaticUserAuthenticator(domain, userName, password);
FileSystemOptions opts = new FileSystemOptions();

DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts, auth);
FileObject fo = VFS.getManager().resolveFile(exportLocation + fileName, opts);
FileContent fileContent = fo.getContent();

CSVPrinter csvPrinter = new CSVPrinter((Appendable) fileContent.getOutputStream(),
                    CSVFormat.DEFAULT.withDelimiter(';'));

I got rid of the BufferedWriter and replaced it with a FileContent instance. Now I'm getting the org.apache.commons.vfs2.FileSystemException: Could not write to "file:////*PATH*/*TO*/*CSV_FILE*.csv".

Now, my .csv file path contains the two backslashes at the beginning because if I remove them, the line FileObject fo = VFS.getManager().resolveFile(exportLocation + fileName, opts); will produce the following exception: org.apache.commons.vfs2.FileSystemException: Could not find file with URI "*PATH*\*TO*\*CSV_FILE*.csv" because it is a relative path, and no base URI was provided. Naturally, this happens because the two backslashes point to a file in a folder rather than the URI.

My problem now is: how can I keep the backslashes for the required line, and remove them when writing to a file in this line: CSVPrinter csvPrinter = new CSVPrinter((Appendable) fileContent.getOutputStream(), CSVFormat.DEFAULT.withDelimiter(';'));?

Plus, I can see now that this last exception was caused by this: java.io.FileNotFoundException: *PATH*\*TO*\*CSV_FILE*.csv (Access is denied) which would mean that I still haven't been able to pass the authentication.


Solution

  • Well, I've given up this approach, so I've tried using jcifs, and got it working.

    CIFSContext base = SingletonContext.getInstance();
    CIFSContext authed1 = base.withCredentials(new NtlmPasswordAuthenticator(domain, userName, password));
    
    SmbFile sFile = new SmbFile("smb://" + exportLocation + fileName, authed1);
    SmbFileOutputStream sfos = new SmbFileOutputStream(sFile);
    OutputStreamWriter out = new OutputStreamWriter(sfos);
    
    CSVPrinter csvPrinter = new CSVPrinter(out, CSVFormat.DEFAULT.withDelimiter(';'));
    

    Sorry I couldn't figure out what was wrong with my apache-commons-vfs code.