I am writing a custom fuse Mirror File System (in Ubuntu using FUSE-JNA). By mirror I mean, It will read from and write into a directory of local file system.
I implemented getattr, create, and read operation as below. All these work perfectly.
...
private final String mirroredFolder = "./target/mirrored";
...
...
public int getattr(final String path, final StatWrapper stat)
{
File f = new File(mirroredFolder+path);
//if current path is of file
if (f.isFile())
{
stat.setMode(NodeType.FILE,true,true,true,true,true,true,true,true,true);
stat.size(f.length());
stat.atime(f.lastModified()/ 1000L);
stat.mtime(0);
stat.nlink(1);
stat.uid(0);
stat.gid(0);
stat.blocks((int) ((f.length() + 511L) / 512L));
return 0;
}
//if current file is of Directory
else if(f.isDirectory())
{
stat.setMode(NodeType.DIRECTORY);
return 0;
}
return -ErrorCodes.ENOENT();
}
below create method creates new file in mirrored folder
public int create(final String path, final ModeWrapper mode, final FileInfoWrapper info)
{
File f = new File(mirroredFolder+path);
try {
f.createNewFile();
mode.setMode(NodeType.FILE, true, true, true);
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
read method reads file from mirrored folder
public int read(final String path, final ByteBuffer buffer, final long size, final long offset, final FileInfoWrapper info)
{
String contentOfFile=null;
try {
contentOfFile= readFile(mirroredFolder+path);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
final String s = contentOfFile.substring((int) offset,
(int) Math.max(offset, Math.min(contentOfFile.length() - offset, offset + size)));
buffer.put(s.getBytes());
return s.getBytes().length;
}
But my write operation is not working.
Below is my Write method, which is incomplete.
public int write(final String path, final ByteBuffer buf, final long bufSize, final long writeOffset,
final FileInfoWrapper wrapper)
{
return (int) bufSize;
}
When I run it in Debugger mode, the path arguments shows Path=/.goutputstream-xxx (where xxx is random alphanumeric each time write method is called)
Please guide me how to correctly implement write operation.
Just write to the filename you're given. How do I create a file and write to it in Java?
The reason you're seeing path=/.goutputstream-xxx is because of https://askubuntu.com/a/151124. This isn't a bug in fuse-jna.
Related
To merge Storage files in Codename One I elaborated this solution:
/**
* Merges the given list of Storage files in the output Storage file.
* #param toBeMerged
* #param output
* #throws IOException
*/
public static synchronized void mergeStorageFiles(List<String> toBeMerged, String output) throws IOException {
if (toBeMerged.contains(output)) {
throw new IllegalArgumentException("The output file cannot be contained in the toBeMerged list of input files.");
}
// Note: the temporary file used for merging is placed in the FileSystemStorage because it offers the method
// openOutputStream(String file, int offset) that allows appending to a stream. Storage doesn't have a such method.
long writtenBytes = 0;
String tempFile = FileSystemStorage.getInstance().getAppHomePath() + "/tempFileUsedInMerge";
for (String partialFile : toBeMerged) {
InputStream in = Storage.getInstance().createInputStream(partialFile);
OutputStream out = FileSystemStorage.getInstance().openOutputStream(tempFile, (int) writtenBytes);
Util.copy(in, out);
writtenBytes = FileSystemStorage.getInstance().getLength(tempFile);
}
Util.copy(FileSystemStorage.getInstance().openInputStream(tempFile), Storage.getInstance().createOutputStream(output));
FileSystemStorage.getInstance().delete(tempFile);
}
This solution is based on the API FileSystemStorage.openOutputStream(String file, int offset), that is the only API that I found to allow to append the content of a file to another.
Are there other API that can be used to append or merge files?
Thank you
Since you end up copying everything to a Storage entry I don't see the value of using FileSystemStorage as an intermediate merging tool.
The only reason I can think of is integrity of the output file (e.g. if failure happens while writing) but that can happen here too. You can guarantee integrity by setting a flag e.g. creating a file called "writeLock" and deleting it when write has finished successfully.
To be clear I would copy like this which is simpler/faster:
try(OutputStream out = Storage.getInstance().createOutputStream(output)) {
for (String partialFile : toBeMerged) {
try(InputStream in = Storage.getInstance().createInputStream(partialFile)) {
Util.copyNoClose(in, out, 8192);
}
}
}
I'm writing a method to output to several output streams at once, the way I got it set up right now is that I have a LogController, LogFile and LogConsole, the latter two are implementations of the Log interface.
What I'm trying to do right now adding a method to the LogController that attaches any implementation of the Log interface.
How I want to do this is as follows: in the LogController I have an associative array, in which I store pointers to Log objects. When the writeOut method of the LogController is called, I want it to then run over the elements of the array and call their writeOut methods too. The latter I can do, but the previous is proving to be difficult.
Mage/Utility/LogController.d
module Mage.Utility.LogController;
import std.stdio;
interface Log {
public void writeOut(string s);
}
class LogController {
private Log*[string] m_Logs;
public this() {
}
public void attach(string name, ref Log l) {
foreach (string key; m_Logs.keys) {
if (name is key) return;
}
m_Logs[name] = &l;
}
public void writeOut(string s) {
foreach (Log* log; m_Logs) {
log.writeOut(s);
}
}
}
Mage/Utility/LogFile.d
module Mage.Utility.LogFile;
import std.stdio;
import std.datetime;
import Mage.Utility.LogController;
class LogFile : Log {
private File fp;
private string path;
public this(string path) {
this.fp = File(path, "a+");
this.path = path;
}
public void writeOut(string s) {
this.fp.writefln("[%s] %s", this.timestamp(), s);
}
private string timestamp() {
return Clock.currTime().toISOExtString();
}
}
I've already tried multiple things with the attach functions, and none of them. The build fails with the following error:
Mage\Root.d(0,0): Error: function Mage.Utility.LogController.LogController.attach (string name, ref Log l) is not callable using argument types (string, LogFile)
This is the incriminating function:
public void initialise(string logfile = DEFAULT_LOG_FILENAME) {
m_Log = new LogController();
LogFile lf = new LogFile(logfile);
m_Log.attach("Log File", lf);
}
Can anyone tell me where I'm going wrong here? I'm stumped and I haven't been able to find the answer anywhere. I've tried a multitude of different solutions and none of them work.
Classes and interfaces in D are reference types, so Log* is redundant - remove the *. Similarly, there is no need to use ref in ref Log l - that's like taking a pointer by reference in C++.
This is the cause of the error message you posted - variables passed by reference must match in type exactly. Removing the ref should solve the error.
In my app I tried to pass the file path from one activity to another activity using intent.In my receiving activity I got the file path as "null".But when I print the file in first activity it prints the path.From my second activity I attach that file to mail using Gmailsender.This was the code I tried,
private void startRecord()
{
File file = new File(Environment.getExternalStorageDirectory(), "test.pcm");
try
{
file.createNewFile();
OutputStream outputStream = new FileOutputStream(file);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream);
int minBufferSize = AudioRecord.getMinBufferSize(8000,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
short[] audioData = new short[minBufferSize];
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
8000,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
minBufferSize);
audioRecord.startRecording();
while(recording)
{
int numberOfShort = audioRecord.read(audioData, 0, minBufferSize);
for(int i = 0; i < numberOfShort; i++)
{
dataOutputStream.writeShort(audioData[i]);
}
}
audioRecord.stop();
audioRecord.release();
dataOutputStream.close();
}
catch (IOException e)
{
e.printStackTrace();
}
String audiofile;
audiofile=file.getAbsolutePath();
System.out.println("File Path::::"+audiofile);
}
Intent is,
Intent sigout=new Intent(getApplicationContext(),WeeklyendActivity.class);
sigout.putExtra("mnt/sdcard-test.pcm",audiofile);
startActivity(sigout);
In my receiving activity,
String patty=getIntent().getStringExtra("mnt/sdcard-text.pcm");
System.out.println("paathhhy frfom ::"+patty);
It prints null.Can anyone help me how to get the file path.And more thing I am not sure whether the audio would save in that file correctly?
Please anyone help me!!!Thanks in advance!
Based on your information that audioFile is a variable of type File, when you do this:
sigout.putExtra("mnt/sdcard-test.pcm",audiofile);
you are putting a File object in the extras Bundle. Then, when you try to get the extra from the Bundle you do this:
String patty=getIntent().getStringExtra("mnt/sdcard-text.pcm");
However, the object in this extra is of type File, not type String. This is why you are getting null.
If you only want to pass the name of the file, then put the extra like this:
sigout.putExtra("mnt/sdcard-test.pcm",audiofile.getAbsolutePath());
I'm learning java and I have a question regarding reading from file
i want to read only numbers from file that contains strings as well.
here is an example of my file:
66.56
"3
JAVA
3-43
5-42
2.1
1
and here is my coding:
public class test {
public static void main (String [] args){
if (0 < args.length) {
File x = new File(args[0]);
try{
Scanner in = new Scanner( new FileInputStream(x));
ArrayList<Double> test = new ArrayList<>();
while(in.hasNext()){
if(in.hasNextDouble()){
Double f=in.nextDouble();
test.add(f);}
else
{in.next();}
}
catch(IOException e) { System.err.println("Exception during reading: " + e); }
}
my problem is it only add 66.56,2.1 and 1
it doesn't add 3 after "3 or it ignores 3-43 and 5-42
can you tell me how to skip Strings and only add doubles here?
thanks
All the said three ie; "3, 3-43 and 4-42 are strings
Either u read a string and split it and check for number at " and - or you put in a space between characters and integers.
The JVM after compilation would treat it all as string if it cannot be converted to a double.
And the File reader wont stop reading till at least a space or a newline.
Hence your code would never work the way you intend it to unless you do as I said above.
Solution 1:
Change your input file to something like this:
66.56
" 3
JAVA
3 - 43
5 - 42
2.1
1
Solution 2:
Considering the highly variable nature of your input file I am posting a solution only made for your current input. If the input changes a more versatile algorithm would need to be implemented.
public static void main(String[] args) {
File x = new File(args[0]);
try {
Scanner in = new Scanner(new FileInputStream(x));
ArrayList<Double> test = new ArrayList<>();
while (in.hasNext()) {
if (in.hasNextDouble()) {
Double f = in.nextDouble();
test.add(f);
} else {
String s=in.next();
if(s.contains("\"")){
String splits[]=s.split("\"");
test.add(Double.parseDouble(splits[1]));
}
else if (s.contains("-")){
String splits[]=s.split("-");
test.add(Double.parseDouble(splits[0]));
test.add(Double.parseDouble(splits[1]));
}
}
}
System.out.println(test);
} catch (IOException e) {
System.err.println("Exception during reading: " + e);
}
}
You can write custom Type Sensor Utility class to check whether the object can be converted to Integer or not. I would approach to this problem like this.
Moreover I can see that you have values like 2.1 and " 3 to handle these scenarios write additional methods like isDoubleType() or isLongType() etc.
Also you need to write some custom logic to solve this problem.
public class TypeSensor {
public String inferType(String value) throws NullValueException {
int formatIndex = -1;
if (null == value) {
throw new NullValueException("Value provided for type inference was null");
}else if (this.isIntegerType(value)) {
return "Integer";
}else{
LOGGER.info("Value " + value + " doesnt fit to any predefined types. Defaulting to String.");
return "String";
}
}
}
private boolean isIntegerType(String value) {
boolean isParseable = false;
try {
Integer.parseInt(value);
LOGGER.info("Parsing successful for " + value + " to Integer.");
isParseable = true;
} catch (NumberFormatException e) {
LOGGER.error("Value " + value + " doesn't seem to be of type Integer. This is not fatal. Exception message is->"
+ e.getMessage());
}
return isParseable;
}
}
In a nutshell, since GAE cannot write to a filesystem, I have decided to persist my data into the datastore (using JDO). Now, I will like to retrieve the data byte by byte and pass it to the client as an input stream. There's code from the gwtupload library(http://code.google.com/p/gwtupload/) (see below) which breaks on GAE because it writes to the system filesystem. I'll like to be able to provide a GAE ported solution.
public static void copyFromInputStreamToOutputStream(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[100000];
while (true) {
synchronized (buffer) {
int amountRead = in.read(buffer);
if (amountRead == -1) {
break;
}
out.write(buffer, 0, amountRead);
}
}
in.close();
out.flush();
out.close();
}
One work around I have tried (didn't work) is to retrieve the data from the datastore as a resource like this:
InputStream resourceAsStream = null;
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Query q = pm.newQuery(ImageFile.class);
lf = q.execute();
resourceAsStream = getServletContext().getResourceAsStream((String) pm.getObjectById(lf));
} finally {
pm.close();
}
if (lf != null) {
response.setContentType(receivedContentTypes.get(fieldName));
copyFromInputStreamToOutputStream(resourceAsStream, response.getOutputStream());
}
I welcome your suggestions.
Regards
Store data in a byte array, and use a ByteArrayInputStream or ByteArrayOutputStream to pass it to libraries that expect streams.
If by 'client' you mean 'HTTP client' or browser, though, there's no reason to do this - just deal with regular byte arrays on your end and send them to/from the user as you would any other data. The only reason to mess around with streams like this is if you have some library that expects them.