In my program I need to read in a config file. Unfortunately every attempt to read it ends without getting the data correctly. Debugging showed that the inputReader always is null. The config file is in my resources folder. Can’t it be found like that or why is the inputReader only null?
private String result;
private final Properties property = new Properties();
public String getString(ConfigType type) {
InputStream inputReader = null;
try {
inputReader = getClass().getResourceAsStream("/resources/config");
if (inputReader != null) {
property.load(inputReader);
inputReader.close();
result = property.getProperty(type.getValue());
}
} catch (IOException exception){
}
}
AFAIK, the reason behind null is invalid directory path.
don't use / in the directory "**/**resources/yourfile" if you don't have any root or parent directory of resource folder.
You don't need to assign null in your inputStream.
InputStream inputStream = getClass().getResourceAsStream("resources/config.properties");
Should work.
Related
The application KDE Connect allows remotely browsing an Android device from a desktop computer through SFTP. Since Android 4.4, developers don't have write permission to SD cards directly through the filesystem anymore. So I am trying to port the SFTP module using the Storage Access Framework (DocumentFile, etc.)
I am taking the permission with an Intent.ACTION_OPEN_DOCUMENT_TREE and FLAG_GRANT_WRITE_URI_PERMISSION and passing the context to my classes.
I am able to create new empty files, rename files and delete files on the SD card inside my class so I believe I am getting the necessary permissions. However, transferring a file results in an empty file (0 bytes) being created. I can see the transfer taking a certain time and a progress bar on the desktop side, so it doesn't just abort.
Here is the relevant part of the SftpSubsystem class from the Apache SSHD library (see doc here) with my own comments to explain what's going on:
public class SftpSubsystem implements Command, Runnable, SessionAware, FileSystemAware {
// This method receives a buffer from an InputStream and processes it
// according to its type. In this situation, it would also contain
// a block of the file being transferred (4096 bytes)
protected void process(Buffer buffer) {
int type = buffer.getByte();
switch (type) {
case WRITE:
FileHandle fh = getHandleFromString(buffer.getString());
long offset = buffer.getLong();
byte[] data = buffer.getBytes();
fh.write(data, offset);
break;
// other cases
}
}
// This class is a handle to a file (duh) with
// an OutputStream to write and InputStream to read
protected static class FileHandle {
SshFile file;
OutputStream output;
long outputPos;
InputStream input;
long inputPos;
// Method called inside process()
public void write(byte[] data, long offset) throws IOException {
if (output != null && offset != outputPos) {
IoUtils.closeQuietly(output);
output = null;
}
if (output == null) {
// This is called once at the start of the transfer.
// This is what I think I need to rewrite to make
// it work with DocumentFile objects.
output = file.createOutputStream(offset);
}
output.write(data);
outputPos += data.length;
}
}
}
The original implementation of createOutputStream() that I want to rewrite because RandomAccessFile doesn't work with DocumentFile:
public class NativeSshFile implements SshFile {
private File file;
public OutputStream createOutputStream(final long offset)
throws IOException {
// permission check
if (!isWritable()) {
throw new IOException("No write permission : " + file.getName());
}
// move to the appropriate offset and create output stream
final RandomAccessFile raf = new RandomAccessFile(file, "rw");
try {
raf.setLength(offset);
raf.seek(offset);
// The IBM jre needs to have both the stream and the random access file
// objects closed to actually close the file
return new FileOutputStream(raf.getFD()) {
public void close() throws IOException {
super.close();
raf.close();
}
};
} catch (IOException e) {
raf.close();
throw e;
}
}
}
One of the ways I tried to implement it:
class SimpleSftpServer {
static class AndroidSshFile extends NativeSshFile {
// This is the DocumentFile that is stored after
// create() created the empty file
private DocumentFile docFile;
public OutputStream createOutputStream(final long offset) throws IOException {
// permission check
if (!isWritable()) {
throw new IOException("No write permission : " + docFile.getName());
}
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(docFile.getUri(), "rw");
FileDescriptor fd = pfd.getFileDescriptor();
try {
android.system.Os.lseek(fd, offset, OsConstants.SEEK_SET);
} catch (ErrnoException e) {
Log.e("SimpleSftpServer", "" + e);
return null;
}
return new FileOutputstream(fd, offset);
}
}
}
I also tried a simple (the offset is ignored but it's just a test):
public OutputStream createOutputStream(final long offset) throws IOException {
// permission check
if (!isWritable()) {
throw new IOException("No write permission : " + docFile.getName());
}
return context.getContentResolver().openOutputStream(docFile.getUri());
}
I also tried with a FileChannel and to flush and sync the FileOutputStream.
Any idea why I end up with an empty file?
EDIT: here is a small example of a test I did to just write a new file from an existing file. It works, but this is not what I actually want to do (see code above) but I thought I'd provide an example to show that I understand the basics of how to write to an OutputStream.
private void createDocumentFileFromFile() {
File fileToRead = new File("/storage/0123-4567/lady.m4a");
File fileToWrite = new File("/storage/0123-4567/lady2.m4a");
File dir = fileToWrite.getParentFile();
DocumentFile docDir = DocumentFile.fromTreeUri(context, SimpleSftpServer.externalStorageUri);
try {
DocumentFile createdFile = docDir.createFile(null, fileToWrite.getName());
Uri uriToRead = Uri.fromFile(fileToRead);
InputStream in = context.getContentResolver().openInputStream(uriToRead);
OutputStream out = context.getContentResolver().openOutputStream(createdFile.getUri());
try {
int nbOfBytes = 0;
final int BLOCKSIZE = 4096;
byte[] bytesRead = new byte[BLOCKSIZE];
while (true) {
nbOfBytes = in.read(bytesRead);
if (nbOfBytes == -1) {
break;
}
out.write(bytesRead, 0, nbOfBytes);
}
} finally {
in.close();
out.close();
}
} catch (IOException e) {
}
}
"When using ACTION_OPEN_DOCUMENT_TREE, your app gains access only to the files in the directory that the user selects. You don't have access to other apps' files that reside outside this user-selected directory.
This user-controlled access allows users to choose exactly what content they're comfortable sharing with your app."
This means, you can only read/write/delete the content/meta data of already existing files or in sub directories in the selected directory, the scope that the user accept to be "comfortable" with.
Actually the user granted permmision to a list of Uri's in this folder for ea file/sub directory there is seperate uri permmision.
Now for example if I will try to create new file in the selected Uri using DocumentFile Ill success but if i will try to outputatream new data to this file I will fail because the user did not grant permision to write to this newly created file.
He only granted to write in the directory path level, means create new file here.
So same happens when you try to move/transfer file to other path that does not have permission from the user.
Path can be folder or file and for ea new path the user needs to grant new access.
move file = new path
write to just created file = new path
I have tried in multiple ways to load the property file from the resource folder.
Every time, I'm getting a file not found exception. My code is as follows:
Properties prop = new Properties();
FileInputStream inputStream = new FileInputStream("/resource/excelfilepath.properties");
prop.load(inputStream);
String path = prop.getProperty("excelPath");
System.out.println("Excel File Path "+ path);
My project structure looks as follows,
What is the needed structure of the file path literal?
I don't think that you really want to read a ....properties file from web resources. That way the content is visible to all users that access your server - as long as you don't hide it explicitly in web.xml.
It's much more common to put it into the classpath next to your accessing class. That way you can access it with the classloader and it is not visible to the webusers anymore:
Properties prop = new Properties();
prop.load(CreateUser.class.getResourceAsStream("excelfilepath.properties"));
But as you are using Liferay, you should use its configuration as well. Just add the property UserCreationPortlet.excelPath to your portal-ext.properties and use:
String path = PrefsPropsUtil.getString("UserCreationPortlet.excelPath", defaultPath);
You need to tell to the server where your root folders are :
With Tomcat : in the catalina.properties
append the properties shared.loader with yours.
With Jboss : Edit jboss-service.xml in your conf folder
<classpath codebase="${jboss.home.url}/server/default/lib//proprietes/rootFolder" archives="*"/>
I would advice to create a classe to load your properties :
Like :
public static Properties charger(Class<?> pClass, String pFilename) {
Properties aProperties = null;
try {
InputStream aIs = null;
File aFile = new File(pFilename);
if (!aFile.isAbsolute()) {
aIs = pClass.getClassLoader().getResourceAsStream(pFilename);
if (aIs == null) {
return null;
}
} else if (!aFile.exists()) {
return null;
}
if (aIs == null)
aIs = new FileInputStream(aFile);
InputStreamReader reader = new InputStreamReader(aIs, "UTF-8");
aProperties = new Properties();
aProperties.clear();
aProperties.load(reader);
reader.close();
aIs.close();
} catch (FileNotFoundException e) {
LOG.error("Catch FileNotFoundException : ", e);
} catch (IOException e) {
LOG.error("Catch IOException : ", e);
}
return aProperties;
}
Then call your new class with the property that you wish :
protected static final Properties property = ChargeurProprietes.charger( .class,"PATH");
property.getProperty(NAME OF YOUR PROPERTY);
I am passing a file as input stream to parser.parse() method while using apache tika library to convert file to text.The method throws an exception (displayed below) but the input stream is closed in the finally block successfully. Then while renaming the file, the File.renameTo method from java.io returns false. I am not able to rename/move the file despite successfully closing the inputStream. I am afraid another instance of file is created, while parser.parse() method processess the file, which doesn't get closed till the time exception is throw. Is that possible? If so what should I do to rename the file.
The Exception thrown while checking the content type is
java.lang.NoClassDefFoundError: Could not initialize class com.adobe.xmp.impl.XMPMetaParser
at com.adobe.xmp.XMPMetaFactory.parseFromBuffer(XMPMetaFactory.java:160)
at com.adobe.xmp.XMPMetaFactory.parseFromBuffer(XMPMetaFactory.java:144)
at com.drew.metadata.xmp.XmpReader.extract(XmpReader.java:106)
at com.drew.imaging.jpeg.JpegMetadataReader.extractMetadataFromJpegSegmentReader(JpegMetadataReader.java:112)
at com.drew.imaging.jpeg.JpegMetadataReader.readMetadata(JpegMetadataReader.java:71)
at org.apache.tika.parser.image.ImageMetadataExtractor.parseJpeg(ImageMetadataExtractor.java:91)
at org.apache.tika.parser.jpeg.JpegParser.parse(JpegParser.java:56)
at org.apache.tika.parser.CompositeParser.parse(CompositeParser.java:244)
at org.apache.tika.parser.CompositeParser.parse(CompositeParser.java:244)
at org.apache.tika.parser.AutoDetectParser.parse(AutoDetectParser.java:121)
Please suggest any solution. Thanks in advance.
public static void main(String args[])
{
InputStream is = null;
StringWriter writer = new StringWriter();
Metadata metadata = new Metadata();
Parser parser = new AutoDetectParser();
File file = null;
File destination = null;
try
{
file = new File("E:\\New folder\\testFile.pdf");
boolean a = file.exists();
destination = new File("E:\\New folder\\test\\testOutput.pdf");
is = new FileInputStream(file);
parser.parse(is, new WriteOutContentHandler(writer), metadata, new ParseContext()); //EXCEPTION IS THROWN HERE.
String contentType = metadata.get(Metadata.CONTENT_TYPE);
System.out.println(contentType);
}
catch(Exception e1)
{
e1.printStackTrace();
}
catch(Throwable t)
{
t.printStackTrace();
}
finally
{
try
{
if(is!=null)
{
is.close(); //CLOSES THE INPUT STREAM
}
writer.close();
}
catch(Exception e2)
{
e2.printStackTrace();
}
}
boolean x = file.renameTo(destination); //RETURNS FALSE
System.out.println(x);
}
This might be due to other processes are still using the file, like anti-virus program and also it may be a case that any other processes in your application may possessing a lock.
please check that and deal with that, it may solve your problem.
I am trying to load a property file from within a jar file but not able do so.
Following is the code of class in which i am loading the file
public class PropertyClass {
private static Properties properties;
public String getProperty(String propertyName) {
try {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("resources/test.properties");
System.out.println("Input Stream " + inputStream);
properties.load(inputStream);
inputStream.close();
if (properties == null) {
System.out.println("Properties null");
}
} catch (IOException e){
e.printStackTrace();
}
return properties.getProperty(propertyName);
}
}
The class file and the property file both are packed inside the jar. But when i am trying load the file from another method it gives following error :-
Input Stream - sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream#9304b1
Exception in thread "main" java.lang.NullPointerException
at PropertyClass.getProperty(PropertyClass.java:16)
It does not show input stream as null
Following bit is the line 16 in my code -
properties.load(inputStream);
Any help on this
You need to initalise your Properties object before you can call properties.load():
private static Properties properties = new Properties();
I have a config.properties file at the root of my blackberry project (same place as Blackberry_App_Descriptor.xml file), and I try to access the file to read and write into it.
See below my class:
public class Configuration {
private String file;
private String fileName;
public Configuration(String pathToFile) {
this.fileName = pathToFile;
try {
// Try to load the file and read it
System.out.println("---------- Start to read the file");
file = readFile(fileName);
System.out.println("---------- Property file:");
System.out.println(file);
} catch (Exception e) {
System.out.println("---------- Error reading file");
System.out.println(e.getMessage());
}
}
/**
* Read a file and return it in a String
* #param fName
* #return
*/
private String readFile(String fName) {
String properties = null;
try {
System.out.println("---------- Opening the file");
//to actually retrieve the resource prefix the name of the file with a "/"
InputStream is = this.getClass().getResourceAsStream(fName);
//we now have an input stream. Create a reader and read out
//each character in the stream.
System.out.println("---------- Input stream");
InputStreamReader isr = new InputStreamReader(is);
char c;
System.out.println("---------- Append string now");
while ((c = (char)isr.read()) != -1) {
properties += c;
}
} catch (Exception e) {
}
return properties;
}
}
I call my class constructor like this:
Configuration config = new Configuration("/config.properties");
So in my class, "file" should have all the content of the config.properties file, and the fileName should have this value "/config.properties".
But the "name" is null because the file cannot be found...
I know this is the path of the file which should be different, but I don't know what i can change... The class is in the package com.mycompany.blackberry.utils
Thank you!
I think you need to put the config.properties file into a source folder when you build the project, you can create a "resources" folder as a src folder and put the config file in it, than you can get the file in the app
Try putting the file in the same package as the class?
Class clazz = Class.forName("Configuration");
InputStream is = addFile.getResourceAsStream(fName);