Convert SmbFile to Java IO File - java

My Java application requires access to a large excel file (1GB+ in size) saved on remote shared folder. I'm using SmbFile to get the file with authentication.
Note: Downloading of the file is not an option mainly for size reasons.
The problem is that I need the excel file to be a Java IO File and not SmbFile since the other libraries that I'm using to parse the excel only accepts Java IO File.
Is there any way to convert this SmbFile into a Java compatible File?

See implementation details of your library:
This library will take a provided InputStream and output it to the file system. (...) Once the file is created, it is then streamed into memory from the file system.
The reason for needing the stream being outputted in this manner has to do with how ZIP files work. Because the XLSX file format is basically a ZIP file, it's not possible to find all of the entries without reading the entire InputStream.
(...) This library works by reading out the stream into a temporary file. As part of the auto-close action, the temporary file is deleted.
If you need more control over how the file is created/disposed of, there is an option to initialize the library with a java.io.File. This file will not be written to or removed
So it doesn't matter if you use the File or InputStream API - the whole file will need to be downloaded anyhow.
The simplest solution is to pass the SmbFile.getInputStream() to
StreamingReader.builder().read(smbFile.getInputStream())
but alternatively you can first download the file eg. by means of IOUtils.copy() or Files.copy()
File file = new File("...");
try (
in = smbFile.getInputStream();
out = new FileOutputStream(file)
) {
IOUtils.copy(in, out);
}
or
try (in = smbFile.getInputStream()) {
Files.copy(smbFile.getInputStream(), file.toPath());
}
and pass file to
StreamingReader.builder().read(file)

Using Apache Commons IO library
https://mvnrepository.com/artifact/commons-io/commons-io
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", "user", "key");
SmbFile smbFile = new SmbFile("smb://IP/pitoka.tmp", auth)
InputStream initialStream = smbFile.getInputStream();
File targetFile = new File("/tmp/pitoka.tmp");
FileUtils.copyInputStreamToFile(initialStream, targetFile);
I hope help you.

jcifs.smb.SmbFile smbFile = new SmbFile("smb://host/fileShare/.../file");
java.io.File javaFile = new File(smbFile.getUncPath());
System.out.println(smbFile);
System.out.println(javaFile);
Output
smb://host/fileShare/.../file
\\host\fileShare\...\file
javadoc of smbFile.getUncPath() says
Retuns the Windows UNC style path with backslashs intead of forward
slashes.
I am using jcifs-1.3.17.jar on Windows 10.

Recently i had a similar situation, however, I hadn't found a good solution in the internet, but I wrote a basic code that did what I need easily.
In your case, you will need to copy the excel file from the source (Remote Directory) using SmbFile with authentication to the destination (Local Directory) and only after, convert the excel file path of the destination (getCanonicalPath() function) and convert it from SmbFile format to File format with the code below.
After, create your File object with the file destination path and do what you want.
I use JCIFS to work with remote shared directories using the SMBFILE class.
First, you need to import the main libraries:
import java.io.File;
import java.io.IOException;
import jcifs.smb.SmbFile;
Second, you need to create a static method to convert from SmbFile format to File format:
/**
* This method convert a directory path from SmbFile format to File format.<br />
* <p><strong>Sintax:</strong> <br /> convertSmbFileToFile("Canonical Path")</p>
* <p><strong>Example:</strong> <br /> convertSmbFileToFile("smb://localhost/D$/DOCUMENTOS/workspace/tests2/access")</p>
* #param smbFileCanonicalPath String
* #see String
*/
public static String convertSmbFileToFile(String smbFileCanonicalPath) {
String[] tempVar = smbFileCanonicalPath.substring(6).replace("$", ":").split("/");
String bar = "\\";
String finalDirectory = "";
for (int i = 1; i < tempVar.length; i++) {
finalDirectory += tempVar[i] + bar;
if (i == tempVar.length - 1) {
finalDirectory = finalDirectory.substring(0,finalDirectory.length()-1);
}
}
return finalDirectory;
}
Opcional, you could also create a static method to convert from File format to SmbFile format:
/**
* This method convert a directory path from File format to SmbFile format.<br />
* <p><strong>Sintax:</strong> <br /> convertFileToSmbFile("Canonical Path")</p>
* <p><strong>Example:</strong> <br /> convertFileToSmbFile("D:\DOCUMENTOS\workspace\tests2\access")</p>
* #param fileCanonicalPath String
* #see String
*/
public static String convertFileToSmbFile(String fileCanonicalPath) {
return "smb://localhost/" + fileCanonicalPath.toString().replace(":", "$").replace("\\", "/");
}
Finally, you can call the methods like the below example:
String dirDest = "access/";
try {
File localDirFile = new File(dirDest);
SmbFile localSmbDirFile = new SmbFile(convertFileToSmbFile(localDirFile.getCanonicalPath()));
File localDirFile2 = new File(convertSmbFileToFile(localSmbDirFile.getCanonicalPath()));
System.out.println("Original File Format: " + localDirFile.getCanonicalPath());
System.out.println("Original File Format to SmbFile Format: " + localSmbDirFile.getCanonicalPath());
System.out.println("Converted SmbFile Format to File Format: " + localDirFile2.getCanonicalPath());
} catch (IOException e) {
System.err.println("[ERR] IO Exception - " + e);
}
Result of previous code run:
Original File Format: D:\DOCUMENTOS\workspace\tests2\access
Original File Format to SmbFile Format: smb://localhost/D$/DOCUMENTOS/workspace/tests2/access
Converted SmbFile Format to File Format: D:\DOCUMENTOS\workspace\tests2\access
Extra Information: getCanonicalPath()
Maybe this code will help you and I am available to talk about if you want.
Good Luck!

It's just a matter of structure I guess, with SmbFile we have two arguments while with File we have just one argument.
So, my Idea is to declare a File with the same path of the SmbFile and try to handle your file.
For example, in my I want to delete recursively the content of my folder :
SmbFile sFile = new SmbFile(path, auth)
if (sFile.exists()) {
File file = new File(path);
deleteDirectory(file);
}
boolean deleteDirectory(File directoryToBeDeleted) {
File[] allContents = directoryToBeDeleted.listFiles();
if (allContents != null) {
for (File file : allContents) {
deleteDirectory(file);
}
}
return directoryToBeDeleted.delete();
}
I hope this peace of code help you, and sorry for my english !

Related

getResourceAsStream returning Null when reading file [duplicate]

I am trying to read a text file which is set in CLASSPATH system variable. Not a user variable.
I am trying to get input stream to the file as below:
Place the directory of file (D:\myDir) in CLASSPATH and try below:
InputStream in = this.getClass().getClassLoader().getResourceAsStream("SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("/SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("//SomeTextFile.txt");
Place full path of file (D:\myDir\SomeTextFile.txt) in CLASSPATH and try the same above 3 lines of code.
But unfortunately NONE of them are working and I am always getting null into my InputStream in.
With the directory on the classpath, from a class loaded by the same classloader, you should be able to use either of:
// From ClassLoader, all paths are "absolute" already - there's no context
// from which they could be relative. Therefore you don't need a leading slash.
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("SomeTextFile.txt");
// From Class, the path is relative to the package of the class unless
// you include a leading slash, so if you don't want to use the current
// package, include a slash like this:
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
If those aren't working, that suggests something else is wrong.
So for example, take this code:
package dummy;
import java.io.*;
public class Test
{
public static void main(String[] args)
{
InputStream stream = Test.class.getResourceAsStream("/SomeTextFile.txt");
System.out.println(stream != null);
stream = Test.class.getClassLoader().getResourceAsStream("SomeTextFile.txt");
System.out.println(stream != null);
}
}
And this directory structure:
code
dummy
Test.class
txt
SomeTextFile.txt
And then (using the Unix path separator as I'm on a Linux box):
java -classpath code:txt dummy.Test
Results:
true
true
When using the Spring Framework (either as a collection of utilities or container - you do not need to use the latter functionality) you can easily use the Resource abstraction.
Resource resource = new ClassPathResource("com/example/Foo.class");
Through the Resource interface you can access the resource as InputStream, URL, URI or File. Changing the resource type to e.g. a file system resource is a simple matter of changing the instance.
This is how I read all lines of a text file on my classpath, using Java 7 NIO:
...
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
...
Files.readAllLines(
Paths.get(this.getClass().getResource("res.txt").toURI()), Charset.defaultCharset());
NB this is an example of how it can be done. You'll have to make improvements as necessary. This example will only work if the file is actually present on your classpath, otherwise a NullPointerException will be thrown when getResource() returns null and .toURI() is invoked on it.
Also, since Java 7, one convenient way of specifying character sets is to use the constants defined in java.nio.charset.StandardCharsets
(these are, according to their javadocs, "guaranteed to be available on every implementation of the Java platform.").
Hence, if you know the encoding of the file to be UTF-8, then specify explicitly the charset StandardCharsets.UTF_8
Please try
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
Your tries didn't work because only the class loader for your classes is able to load from the classpath. You used the class loader for the java system itself.
To actually read the contents of the file, I like using Commons IO + Spring Core. Assuming Java 8:
try (InputStream stream = new ClassPathResource("package/resource").getInputStream()) {
IOUtils.toString(stream);
}
Alternatively:
InputStream stream = null;
try {
stream = new ClassPathResource("/log4j.xml").getInputStream();
IOUtils.toString(stream);
} finally {
IOUtils.closeQuietly(stream);
}
To get the class absolute path try this:
String url = this.getClass().getResource("").getPath();
Somehow the best answer doesn't work for me. I need to use a slightly different code instead.
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream is = loader.getResourceAsStream("SomeTextFile.txt");
I hope this help those who encounters the same issue.
If you use Guava:
import com.google.common.io.Resources;
we can get URL from CLASSPATH:
URL resource = Resources.getResource("test.txt");
String file = resource.getFile(); // get file path
or InputStream:
InputStream is = Resources.getResource("test.txt").openStream();
Ways to convert an InputStream to a String
To read the contents of a file into a String from the classpath, you can use this:
private String resourceToString(String filePath) throws IOException, URISyntaxException
{
try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filePath))
{
return IOUtils.toString(inputStream);
}
}
Note:
IOUtils is part of Commons IO.
Call it like this:
String fileContents = resourceToString("ImOnTheClasspath.txt");
You say "I am trying to read a text file which is set in CLASSPATH system variable." My guess this is on Windows and you are using this ugly dialog to edit the "System Variables".
Now you run your Java program in the console. And that doesn't work: The console gets a copy of the values of the system variables once when it is started. This means any change in the dialog afterwards doesn't have any effect.
There are these solutions:
Start a new console after every change
Use set CLASSPATH=... in the console to set the copy of the variable in the console and when your code works, paste the last value into the variable dialog.
Put the call to Java into .BAT file and double click it. This will create a new console every time (thus copying the current value of the system variable).
BEWARE: If you also have a User variable CLASSPATH then it will shadow your system variable. That is why it is usually better to put the call to your Java program into a .BAT file and set the classpath in there (using set CLASSPATH=) rather than relying on a global system or user variable.
This also makes sure that you can have more than one Java program working on your computer because they are bound to have different classpaths.
My answer is not exactly what is asked in the question. Rather I am giving a solution exactly how easily we can read a file into out java application from our project class path.
For example suppose a config file name example.xml is located in a path like below:-
com.myproject.config.dev
and our java executable class file is in the below path:-
com.myproject.server.main
now just check in both the above path which is the nearest common directory/folder from where you can access both dev and main directory/folder (com.myproject.server.main - where our application’s java executable class is existed) – We can see that it is myproject folder/directory which is the nearest common directory/folder from where we can access our example.xml file. Therefore from a java executable class resides in folder/directory main we have to go back two steps like ../../ to access myproject. Now following this, see how we can read the file:-
package com.myproject.server.main;
class Example {
File xmlFile;
public Example(){
String filePath = this.getClass().getResource("../../config/dev/example.xml").getPath();
this.xmlFile = new File(filePath);
}
public File getXMLFile() {
return this.xmlFile;
}
public static void main(String args[]){
Example ex = new Example();
File xmlFile = ex.getXMLFile();
}
}
If you compile your project in jar file:
you can put your file in resources/files/your_file.text or pdf;
and use this code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
public class readFileService(){
private static final Logger LOGGER = LoggerFactory.getLogger(readFileService.class);
public byte[] getFile(){
String filePath="/files/your_file";
InputStream inputStreamFile;
byte[] bytes;
try{
inputStreamFile = this.getClass().getResourceAsStream(filePath);
bytes = new byte[inputStreamFile.available()];
inputStreamFile.read(bytes);
} catch(NullPointerException | IOException e) {
LOGGER.error("Erreur read file "+filePath+" error message :" +e.getMessage());
return null;
}
return bytes;
}
}
I am using webshpere application server and my Web Module is build on Spring MVC. The Test.properties were located in the resources folder, i tried to load this files using the following:
this.getClass().getClassLoader().getResourceAsStream("Test.properties");
this.getClass().getResourceAsStream("/Test.properties");
None of the above code loaded the file.
But with the help of below code the property file was loaded successfully:
Thread.currentThread().getContextClassLoader().getResourceAsStream("Test.properties");
Thanks to the user "user1695166".
Use org.apache.commons.io.FileUtils.readFileToString(new File("src/test/resources/sample-data/fileName.txt"));
Don't use getClassLoader() method and use the "/" before the file name. "/" is very important
this.getClass().getResourceAsStream("/SomeTextFile.txt");
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReadFile
{
/**
* * feel free to make any modification I have have been here so I feel you
* * * #param args * #throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// thread pool of 10
File dir = new File(".");
// read file from same directory as source //
if (dir.isDirectory()) {
File[] files = dir.listFiles();
for (File file : files) {
// if you wanna read file name with txt files
if (file.getName().contains("txt")) {
System.out.println(file.getName());
}
// if you want to open text file and read each line then
if (file.getName().contains("txt")) {
try {
// FileReader reads text files in the default encoding.
FileReader fileReader = new FileReader(
file.getAbsolutePath());
// Always wrap FileReader in BufferedReader.
BufferedReader bufferedReader = new BufferedReader(
fileReader);
String line;
// get file details and get info you need.
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
// here you can say...
// System.out.println(line.substring(0, 10)); this
// prints from 0 to 10 indext
}
} catch (FileNotFoundException ex) {
System.out.println("Unable to open file '"
+ file.getName() + "'");
} catch (IOException ex) {
System.out.println("Error reading file '"
+ file.getName() + "'");
// Or we could just do this:
ex.printStackTrace();
}
}
}
}
}
}
you have to put your 'system variable' on the java classpath.

Update Google Doc with Drive API - Format lost

I'm trying to develop a Java program which retrieves a file from the Google Drive and try to reupload it "as is". However, during that process, It loses the format.
Here is how I retrive the file:
private static java.io.File downloadFile(File uploadedFile)
throws IOException {
java.io.File downloadedFile = new java.io.File(parentDir, uploadedFile.getTitle() + UUID.randomUUID().toString());
try (OutputStream out = new FileOutputStream(downloadedFile)) {
drive.files().export(uploadedFile.getId(), "text/html").executeMediaAndDownloadTo(out);
}
return downloadedFile;
}
Here is how I update the file:
private static File updateFile(Drive service, String fileId, File file, java.io.File newContent) throws IOException {
FileContent mediaContent = new FileContent("text/html", newContent);
return service.files().update(fileId, file, mediaContent).execute();
}
And here is how I combine those methods (pretty dummy):
java.io.File downloaded = downloadFile(files.get(0));
updateFile(drive, files.get(0).getId(), files.get(0), downloaded);
This is the file before and after:
The process is fine when I export & re-import the Google file as RTF or PDF, but I really need an editable format. Did I miss something?
This is the expected outcome. PDFs are one way of ensuring the formats are preserved. For Google Docs, not so much.

Resource File Path as String (not streaming)

I don't get it - I'm trying to get the path of a file so that the file (an image) can be included as an attachment in an email.
My system consists of two parts - a web app and a jar. (actually three parts - a common shared jar containing DAOs etc.)
They're both built using maven.
They both contain this image in this path:
src/main/resources/logo_48.png
WebApp:
String logo1 = getClass().getClassLoader().getResource("logo_48.png").getPath();
This works perfectly - both on local (Windows) and Linux
Jar Application:
String logo1 = getClass().getClassLoader().getResource("logo_48.png").getPath(); //doesn't work
I've taken advice from here:
How to access resources in JAR file?
here:
Reading a resource file from within jar
here:
http://www.coderanch.com/t/552720/java/java/access-text-file-JAR
and others
Most answers offer to load the file as a stream etc. but I'm only wishing to get the path assigned to the String. Other resources have led me to hacking the code for hours only to find the end result doesn't work.
After so many instances of /home/kalton/daily.jar!logo_48.png does not exist errors I was frustrated and settled on the following workaround:
Copy the logo_48.png directly to the folder where the jar resides (/home/kalton/)
Alter my jar application code to:
String logo1 = "/home/kalton/logo_48.png";
And it works.
Could anyone show me the right way to get the PATH (as a String) of a file in the resources folder from a JAR that is not unpacked?
This issue was driving me crazy for weeks!
Thanks in advance.
KA.
Adding actual use code of 'path' for clarity of use:
public static MimeMultipart assemble4SO(String logoTop, String emailHTMLText) throws MessagingException, IOException {
MimeMultipart content = new MimeMultipart("related");
String cid = Long.toString(System.currentTimeMillis());
String cidB = cid + "b";
String cssStyle = "";
String body = "<html><head>" + cssStyle + "</head><body><div>" + "<img src='cid:" + cid + "'/>" + emailHTMLText + "<img src='cid:" + cidB + "'/></div></body></html>";
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(body, "text/html; charset=utf-8");
content.addBodyPart(textPart);
//add an inline image
MimeBodyPart imagePart = new MimeBodyPart();
imagePart.attachFile(logoTop);
imagePart.setContentID("<" + cid + ">");
imagePart.setDisposition(MimeBodyPart.INLINE);
content.addBodyPart(imagePart);
.............
From the top…
A .jar file is actually a zip file. A zip file is a single file that acts as an archive. The entries in this archive are not separate files, they're just sequences of compressed bytes within the zip file. They cannot be accessed as individual file names or File objects, ever.
Also important: The getPath method of the URL class does not convert a URL to a file name. It returns the path portion of the URL, which is just the part after the host (and before any query and/or fragment). Many characters are illegal in URLs, and need to be “escaped” using percent encoding, so if you just extract the path directly from a URL, you'll often end up with something containing percent-escapes, which therefore is not a valid file name at all.
Some examples:
String path = "C:\\Program Files";
URL url = new File(path).toURI().toURL();
System.out.println(url); // prints file:/C:/Program%20Files
System.out.println(url.getPath()); // prints /C:/Program%20Files
File file = new File(url.getPath());
System.out.println(file.exists()); // prints false, because
// "Program%20Files" ≠ "Program Files"
 
String path = "C:\\Users\\VGR\\Documents\\résumé.txt";
URL url = new File(path).toURI().toURL();
// Prints file:/C:/Users/VGR/Documents/r%C3%A9sum%C3%A9.txt
System.out.println(url);
// Prints /C:/Users/VGR/Documents/r%C3%A9sum%C3%A9.txt
System.out.println(url.getPath());
File file = new File(url.getPath());
System.out.println(file.exists()); // prints false, because
// "r%C3%A9sum%C3%A9.txt" ≠ "résumé.txt"
Based on your edit, I see that the real reason you want a String is so you can call MimeBodyPart.attachFile. You have two options:
Do the work of attachFile yourself:
URL logo = getClass().getLoader().getResource("logo_48.png");
imagePart.setDataHandler(new DataHandler(logo));
imagePart.setDisposition(Part.ATTACHMENT);
Copy the resource to a temporary file, then pass that file:
Path logoFile = Files.createTempFile("logo", ".png");
try (InputStream stream =
getClass().getLoader().getResourceAsStream("logo_48.png")) {
Files.copy(stream, logoFile, StandardCopyOption.REPLACE_EXISTING);
}
imagePart.attachFile(logoFile.toFile());
As you can see, the first option is easier. The second option also would require cleaning up your temporary file, but you don't want to do that until you've sent off your message, which probably requires making use of a TransportListener.

renaming file name inside a zip file

trying to rename internal file within a zip file without having to extract and then re-zip programatically.
example. test.zip contains test.txt, i want to change it so that test.zip will contain newtest.txt(test.txt renamed to newtest.txt, contents remain the same)
came across this link that works but unfortunately it expects test.txt to exist on the system. In the example the srcfile should exist on the server.
Blockquote Rename file in zip with zip4j
Then icame across zipnote on Linux that does the trick but unfortunately the version i have doesnt work for files >4GB.
Any suggestions on how to accomplish this? prefereably in java.
This should be possible using Java 7 Zip FileSystem provider, something like:
// syntax defined in java.net.JarURLConnection
URI uri = URI.create("jar:file:/directoryPath/file.zip");
try (FileSystem zipfs = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap())) {
Path sourceURI = zipfs.getPath("/pathToDirectoryInsideZip/file.txt");
Path destinationURI = zipfs.getPath("/pathToDirectoryInsideZip/renamed.txt");
Files.move(sourceURI, destinationURI);
}
Using zip4j, I am modifying and re-writing the file headers inside of the central directory section to avoid rewriting the entire zip file:
ArrayList<FileHeader> FHs = (ArrayList<FileHeader>) zipFile.getFileHeaders();
FHs.get(0).setFileName("namename.mp4");
FHs.get(0).setFileNameLength("namename.mp4".getBytes("UTF-8").length);
zipFile.updateHeaders ();
//where updateHeaders is :
public void updateHeaders() throws ZipException, IOException {
checkZipModel();
if (this.zipModel == null) {
throw new ZipException("internal error: zip model is null");
}
if (Zip4jUtil.checkFileExists(file)) {
if (zipModel.isSplitArchive()) {
throw new ZipException("Zip file already exists. Zip file format does not allow updating split/spanned files");
}
}
long offset = zipModel.getEndCentralDirRecord().getOffsetOfStartOfCentralDir();
HeaderWriter headerWriter = new HeaderWriter();
SplitOutputStream splitOutputStream = new SplitOutputStream(new File(zipModel.getZipFile()), -1);
splitOutputStream.seek(offset);
headerWriter.finalizeZipFile(zipModel, splitOutputStream);
splitOutputStream.close();
}
The name field in the local file header section remains unchanged, so there will be a mismatch exception in this library.
It's tricky but maybe problematic, I don't know..

How to read text file from classpath in Java?

I am trying to read a text file which is set in CLASSPATH system variable. Not a user variable.
I am trying to get input stream to the file as below:
Place the directory of file (D:\myDir) in CLASSPATH and try below:
InputStream in = this.getClass().getClassLoader().getResourceAsStream("SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("/SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("//SomeTextFile.txt");
Place full path of file (D:\myDir\SomeTextFile.txt) in CLASSPATH and try the same above 3 lines of code.
But unfortunately NONE of them are working and I am always getting null into my InputStream in.
With the directory on the classpath, from a class loaded by the same classloader, you should be able to use either of:
// From ClassLoader, all paths are "absolute" already - there's no context
// from which they could be relative. Therefore you don't need a leading slash.
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("SomeTextFile.txt");
// From Class, the path is relative to the package of the class unless
// you include a leading slash, so if you don't want to use the current
// package, include a slash like this:
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
If those aren't working, that suggests something else is wrong.
So for example, take this code:
package dummy;
import java.io.*;
public class Test
{
public static void main(String[] args)
{
InputStream stream = Test.class.getResourceAsStream("/SomeTextFile.txt");
System.out.println(stream != null);
stream = Test.class.getClassLoader().getResourceAsStream("SomeTextFile.txt");
System.out.println(stream != null);
}
}
And this directory structure:
code
dummy
Test.class
txt
SomeTextFile.txt
And then (using the Unix path separator as I'm on a Linux box):
java -classpath code:txt dummy.Test
Results:
true
true
When using the Spring Framework (either as a collection of utilities or container - you do not need to use the latter functionality) you can easily use the Resource abstraction.
Resource resource = new ClassPathResource("com/example/Foo.class");
Through the Resource interface you can access the resource as InputStream, URL, URI or File. Changing the resource type to e.g. a file system resource is a simple matter of changing the instance.
This is how I read all lines of a text file on my classpath, using Java 7 NIO:
...
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
...
Files.readAllLines(
Paths.get(this.getClass().getResource("res.txt").toURI()), Charset.defaultCharset());
NB this is an example of how it can be done. You'll have to make improvements as necessary. This example will only work if the file is actually present on your classpath, otherwise a NullPointerException will be thrown when getResource() returns null and .toURI() is invoked on it.
Also, since Java 7, one convenient way of specifying character sets is to use the constants defined in java.nio.charset.StandardCharsets
(these are, according to their javadocs, "guaranteed to be available on every implementation of the Java platform.").
Hence, if you know the encoding of the file to be UTF-8, then specify explicitly the charset StandardCharsets.UTF_8
Please try
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
Your tries didn't work because only the class loader for your classes is able to load from the classpath. You used the class loader for the java system itself.
To actually read the contents of the file, I like using Commons IO + Spring Core. Assuming Java 8:
try (InputStream stream = new ClassPathResource("package/resource").getInputStream()) {
IOUtils.toString(stream);
}
Alternatively:
InputStream stream = null;
try {
stream = new ClassPathResource("/log4j.xml").getInputStream();
IOUtils.toString(stream);
} finally {
IOUtils.closeQuietly(stream);
}
To get the class absolute path try this:
String url = this.getClass().getResource("").getPath();
Somehow the best answer doesn't work for me. I need to use a slightly different code instead.
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream is = loader.getResourceAsStream("SomeTextFile.txt");
I hope this help those who encounters the same issue.
If you use Guava:
import com.google.common.io.Resources;
we can get URL from CLASSPATH:
URL resource = Resources.getResource("test.txt");
String file = resource.getFile(); // get file path
or InputStream:
InputStream is = Resources.getResource("test.txt").openStream();
Ways to convert an InputStream to a String
To read the contents of a file into a String from the classpath, you can use this:
private String resourceToString(String filePath) throws IOException, URISyntaxException
{
try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filePath))
{
return IOUtils.toString(inputStream);
}
}
Note:
IOUtils is part of Commons IO.
Call it like this:
String fileContents = resourceToString("ImOnTheClasspath.txt");
You say "I am trying to read a text file which is set in CLASSPATH system variable." My guess this is on Windows and you are using this ugly dialog to edit the "System Variables".
Now you run your Java program in the console. And that doesn't work: The console gets a copy of the values of the system variables once when it is started. This means any change in the dialog afterwards doesn't have any effect.
There are these solutions:
Start a new console after every change
Use set CLASSPATH=... in the console to set the copy of the variable in the console and when your code works, paste the last value into the variable dialog.
Put the call to Java into .BAT file and double click it. This will create a new console every time (thus copying the current value of the system variable).
BEWARE: If you also have a User variable CLASSPATH then it will shadow your system variable. That is why it is usually better to put the call to your Java program into a .BAT file and set the classpath in there (using set CLASSPATH=) rather than relying on a global system or user variable.
This also makes sure that you can have more than one Java program working on your computer because they are bound to have different classpaths.
My answer is not exactly what is asked in the question. Rather I am giving a solution exactly how easily we can read a file into out java application from our project class path.
For example suppose a config file name example.xml is located in a path like below:-
com.myproject.config.dev
and our java executable class file is in the below path:-
com.myproject.server.main
now just check in both the above path which is the nearest common directory/folder from where you can access both dev and main directory/folder (com.myproject.server.main - where our application’s java executable class is existed) – We can see that it is myproject folder/directory which is the nearest common directory/folder from where we can access our example.xml file. Therefore from a java executable class resides in folder/directory main we have to go back two steps like ../../ to access myproject. Now following this, see how we can read the file:-
package com.myproject.server.main;
class Example {
File xmlFile;
public Example(){
String filePath = this.getClass().getResource("../../config/dev/example.xml").getPath();
this.xmlFile = new File(filePath);
}
public File getXMLFile() {
return this.xmlFile;
}
public static void main(String args[]){
Example ex = new Example();
File xmlFile = ex.getXMLFile();
}
}
If you compile your project in jar file:
you can put your file in resources/files/your_file.text or pdf;
and use this code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
public class readFileService(){
private static final Logger LOGGER = LoggerFactory.getLogger(readFileService.class);
public byte[] getFile(){
String filePath="/files/your_file";
InputStream inputStreamFile;
byte[] bytes;
try{
inputStreamFile = this.getClass().getResourceAsStream(filePath);
bytes = new byte[inputStreamFile.available()];
inputStreamFile.read(bytes);
} catch(NullPointerException | IOException e) {
LOGGER.error("Erreur read file "+filePath+" error message :" +e.getMessage());
return null;
}
return bytes;
}
}
I am using webshpere application server and my Web Module is build on Spring MVC. The Test.properties were located in the resources folder, i tried to load this files using the following:
this.getClass().getClassLoader().getResourceAsStream("Test.properties");
this.getClass().getResourceAsStream("/Test.properties");
None of the above code loaded the file.
But with the help of below code the property file was loaded successfully:
Thread.currentThread().getContextClassLoader().getResourceAsStream("Test.properties");
Thanks to the user "user1695166".
Use org.apache.commons.io.FileUtils.readFileToString(new File("src/test/resources/sample-data/fileName.txt"));
Don't use getClassLoader() method and use the "/" before the file name. "/" is very important
this.getClass().getResourceAsStream("/SomeTextFile.txt");
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReadFile
{
/**
* * feel free to make any modification I have have been here so I feel you
* * * #param args * #throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// thread pool of 10
File dir = new File(".");
// read file from same directory as source //
if (dir.isDirectory()) {
File[] files = dir.listFiles();
for (File file : files) {
// if you wanna read file name with txt files
if (file.getName().contains("txt")) {
System.out.println(file.getName());
}
// if you want to open text file and read each line then
if (file.getName().contains("txt")) {
try {
// FileReader reads text files in the default encoding.
FileReader fileReader = new FileReader(
file.getAbsolutePath());
// Always wrap FileReader in BufferedReader.
BufferedReader bufferedReader = new BufferedReader(
fileReader);
String line;
// get file details and get info you need.
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
// here you can say...
// System.out.println(line.substring(0, 10)); this
// prints from 0 to 10 indext
}
} catch (FileNotFoundException ex) {
System.out.println("Unable to open file '"
+ file.getName() + "'");
} catch (IOException ex) {
System.out.println("Error reading file '"
+ file.getName() + "'");
// Or we could just do this:
ex.printStackTrace();
}
}
}
}
}
}
you have to put your 'system variable' on the java classpath.

Categories