I want to write something to the end of the file every time the file is modified and I'm using this code :
public class Main {
public static final String DIRECTORY_TO_WATCH = "D:\\test";
public static void main(String[] args) {
Path toWatch = Paths.get(DIRECTORY_TO_WATCH);
if (toWatch == null) {
throw new UnsupportedOperationException();
}
try {
WatchService myWatcher = toWatch.getFileSystem().newWatchService();
FileWatcher fileWatcher = new FileWatcher(myWatcher);
Thread t = new Thread(fileWatcher, "FileWatcher");
t.start();
toWatch.register(myWatcher, StandardWatchEventKinds.ENTRY_MODIFY);
t.join();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
and the thread class :
public class FileWatcher implements Runnable{
private WatchService myWatcher;
private Path toWatch;
String content = "Dong\n";
int counter = 0;
public FileWatcher (WatchService myWatcher, Path toWatch) {
this.myWatcher = myWatcher;
this.toWatch = toWatch;
}
#Override
public void run() {
try {
WatchKey key = myWatcher.take();
while (key != null) {
for (WatchEvent event : key.pollEvents()) {
//System.out.printf("Received %s event for file: %s\n", event.kind(), event.context());
//System.out.println(counter);
myWatcher = null;
File file = new File(Main.DIRECTORY_TO_WATCH + "\\" + event.context());
FileWriter fw = new FileWriter(file.getAbsoluteFile(), true);
fw.write(counter + content);
fw.close();
counter++;
myWatcher = toWatch.getFileSystem().newWatchService();
toWatch.register(myWatcher, StandardWatchEventKinds.ENTRY_MODIFY);
// BufferedWriter bwWriter = new BufferedWriter(fw);
// bwWriter.write(content);
// bwWriter.close();
}
key.reset();
key = myWatcher.take();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I want to get in the file something like :
acasc 0dong
dwqcacesv 1dong
terert 2dong
However, now I'm getting this, because it writes too many times in the file:
acasc 0dong
1dong
...
50123dong
If I use System.out.println(counter); it works as I want to (prints the number of file changes correctly), but it goes wild on fw.write(counter + content);
Your thread's write is causing further changes to the file.
Self feeding loop.
Related
I have been given this problem in which if a file is currently getting read, no write operation can occur on it and vice versa, using wait() and notify(). I have tried to come up with a solution but after first read the program only does the write operation and gets stuck. Here's the code
public static boolean LOCK = false;
public synchronized void read() {
String path = "/path/to/file/working.txt";
while (LOCK == true) {
try {
System.out.println("reading paused..");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try (BufferedReader bin = new BufferedReader(new FileReader(path))) {
LOCK = true;
String line = "";
System.out.println("reading now..");
while ((line = bin.readLine()) != null) {
System.out.println(line);
}
LOCK = false;
notify();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public synchronized void write(String word) {
String path = "/path/to/file/working.txt";
while (LOCK == true) {
try {
System.out.println("writing paused..");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(path, true)))) {
System.out.println("writing resumed..");
LOCK = true;
out.println(word);
LOCK = false;
notify();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I passed an String array of fruits as test, lauching read() and write() as seperate threads and the output I'm getting is,
Writing resumed..
reading..
Apple
Writing resumed..
Writing resumed..
Writing resumed..
The output gets written completly but no read operation occurs after the first word. Please can you tell me what I'm doing wrong? Thank you.
Here's the test code,
String[] fruits = { "Apple", "Banana", "Orange", "Cherry", "Date", "ElderBerry", "Marionberry", "Blueberry", };
FileSyncDemo fileDemo = new FileSyncDemo();
Runnable r = () -> {
try {
fileDemo.read();
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Runnable r2 = () -> {
try {
for (int i = 0; i < fruits.length; i++) {
fileDemo.write(fruits[i]);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread t = new Thread(r);
t.start();
Thread t2 = new Thread(r2);
t2.start();
}
I asked a question earlier about extracting RAR archives in Java and someone pointed me to JUnrar. The official site is down but it seems to be quite widely used as I found a lot of discussions about it online.
Could someone show me how to use JUnrar to extract all the files in an archive? I found a little snippet online but it doesn't seem to work. It shows each item in the archive to be a directory even if it is a file.
Archive rar = new Archive(new File("C://Weather_Icons.rar"));
FileHeader fh = rar.nextFileHeader();
while(fh != null){
if (fh.isDirectory()) {
logger.severe("directory: " + fh.getFileNameString() );
}
//File out = new File(fh.getFileNameString());
//FileOutputStream os = new FileOutputStream(out);
//rar.extractFile(fh, os);
//os.close();
fh=rar.nextFileHeader();
}
Thanks.
May be you should also check this snippet code. A copy of which can be found below.
public class MVTest {
/**
* #param args
*/
public static void main(String[] args) {
String filename = "/home/rogiel/fs/home/movies/vp.mp3.part1.rar";
File f = new File(filename);
Archive a = null;
try {
a = new Archive(new FileVolumeManager(f));
} catch (RarException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (a != null) {
a.getMainHeader().print();
FileHeader fh = a.nextFileHeader();
while (fh != null) {
try {
File out = new File("/home/rogiel/fs/test/"
+ fh.getFileNameString().trim());
System.out.println(out.getAbsolutePath());
FileOutputStream os = new FileOutputStream(out);
a.extractFile(fh, os);
os.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RarException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
fh = a.nextFileHeader();
}
}
}
}
I need to log my messages not only into system logs ( as I know, system log buffer is quite short, but I need to see logs for 3-5 days ), but also in a separate text file. Logging must be asynchronous.
Could you give me an advice about which component should I use in this case?
Thanks.
I hope it will be useful for you.
public void appendLog(String text) {
File logFile = new File("sdcard/log.file");
if (!logFile.exists()) {
try {
logFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
//BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
buf.append(text);
buf.newLine();
buf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Don't forget to add permission for android.permission.WRITE_EXTERNAL_STORAGE in Manifest!
Works asynchronously and dose not need to permission !
just remember call the init method from your application in onCreateMethod for initializing the Logger
class Logger {
private static File logFileLoc;
private static ExecutorService logExecutor;
public static void init(Context applicationContext, String logFileName, boolean reCreate) {
logFileLoc = new File(applicationContext.getCacheDir(), logFileName);
if (reCreate && logFileLoc.exists()) logFileLoc.delete();
logExecutor = Executors.newSingleThreadExecutor();
}
public static void log(final String tag, final String msg) {
if (logFileLoc == null) try {
throw new Exception("First you should call init method in your application");
} catch (Exception e) {
e.printStackTrace();
}
Log.d(tag, msg);
logExecutor.execute(new Runnable() {
#Override
public void run() {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(logFileLoc,true));
String timeStamp = DateFormat.getDateTimeInstance().format(new Date(System.currentTimeMillis()));
writer.append(timeStamp + " " + tag + " : " + msg );
writer.newLine();
writer.flush();
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
also you can do the same thing with Timber library for more info :
https://medium.com/#vicky7230/file-logging-with-timber-4e63a1b86a66
I tried to connect with asynchronous socket and read new messages once per second.
I used sample client code (http://www.java2s.com/Tutorials/Java/Java_Network/0080__Java_Network_Asynchronous_Socket_Channels.htm) and in getTextFromUser method I added sleep method (with 1000 ms) and removed read command from user.
Additionally I added additional logic in ReadWriteHandler method. It started work great, but after about one hour program was suspended and has worked (execute my additional logic) not once per second but one per about 10 minutes.
Do you have any idea what might happen?
Part of code:
public void ConnectAsynchr() {
try {
this.channel = AsynchronousSocketChannel.open();
SocketAddress serverAddr = new InetSocketAddress("localhost", PortNumberAsynchr);
Future<Void> result = channel.connect(serverAddr);
try {
result.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.writeLog("ConnAsynch", "Asynchronous connection succesful established", true);
this.connectAsynch = true;
this.attach = new Attachment();
this.attach.channel = this.channel;
this.attach.buffer = ByteBuffer.allocate(16384);
this.attach.isRead = false;
this.attach.mainThread = Thread.currentThread();
ReadWriteHandler readWriteHandler = new ReadWriteHandler();
this.channel.write(this.attach.buffer, this.attach, readWriteHandler);
try {
this.attach.mainThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
this.writeLog("ERROR", e.toString(), false);
e.printStackTrace();
}
}
catch (IOException e) {
this.writeLog("ERROR", e.toString(), false);
System.out.println(e);
}
}
class Attachment {
AsynchronousSocketChannel channel;
ByteBuffer buffer;
Thread mainThread;
boolean isRead;
}
class ReadWriteHandler implements CompletionHandler<Integer, Attachment> {
#Override
public void completed(Integer result, Attachment attach) {
if (attach.isRead) {
attach.buffer.flip();
Charset cs = Charset.forName("UTF-8");
int limits = attach.buffer.limit();
byte bytes[] = new byte[limits];
attach.buffer.get(bytes, 0, limits);
String msg = new String(bytes, cs);
writeLog("Asynchr Msg rec", msg, false);
AsynchrMessLogic(msg);
try {
msg = this.getTextFromUser();
} catch (Exception e) {
e.printStackTrace();
}
if (msg.equalsIgnoreCase("bye")) {
attach.mainThread.interrupt();
return;
}
attach.buffer.clear();
byte[] data = msg.getBytes(cs);
attach.buffer.put(data);
attach.buffer.flip();
attach.isRead = false; // It is a write
attach.channel.write(attach.buffer, attach, this);
}else {
attach.isRead = true;
attach.buffer.clear();
attach.channel.read(attach.buffer, attach, this);
}
}
#Override
public void failed(Throwable e, Attachment attach) {
e.printStackTrace();
}
private String getTextFromUser() throws Exception{
/*System.out.print("\nPlease enter a message (Bye to quit):");
BufferedReader consoleReader = new BufferedReader(
new InputStreamReader(System.in));
String msg = consoleReader.readLine();
*/
Thread.sleep(threadSleep);
String msg="aaa";
return msg;
}
}
I want to remove a line from my file (specifically the second line)
so I have used another file to copy in it ,but using the following code the second file contain exactly the same text.(My original file .txt and my final file .xml)
public static File fileparse() throws SQLException, FileNotFoundException, IOException {
File f=fillfile();//my original file
dostemp = new DataOutputStream(new FileOutputStream(filetemp));
int lineremove=1;
while (f.length()!=0) {
if (lineremove<2) {
read = in.readLine();
dostemp.writeBytes(read);
lineremove++;
}
if (lineremove==2) {
lineremove++;
}
if (lineremove>2) {
read = in.readLine();
dostemp.writeBytes(read);
}
}
return filetemp;
}
You do not read the line if the lineremove is 2 and also you check if it is greater than 2 after you increased it when it was 2. Do it like this:
int line = 1;
String read = null;
while((read = in.readLine()) != null){
if(line!=2)
{
dostemp.writeBytes(read);
}
line++;
}
you can use BufferedReader with the readLine() method to read line by line, check if it a line you want and skip the lines you dont want.
check the docs at: BufferedReader
here is a working example (Not the most beautiful or clean :) ):
public static void main(String[] args) {
// TODO Auto-generated method stub
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader("d:\\test.txt"));
} catch (FileNotFoundException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
PrintWriter out = null ;
try {
out = new PrintWriter (new FileWriter ("d:\\test_out.txt"));
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
String line = null;
int lineNum = 0;
try {
while( (line = in.readLine()) != null) {
lineNum +=1;
if(lineNum == 2){
continue;
}
out.println(line);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
out.flush();
out.close();
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}