Can't give values properly trougth serialization - java

It is going to be a very basic question I suppose, but I've been searching for the answer fo hours and I just can't figure out where's my code go wrong. So: I do serialze an object called SerializableObject, than read it back. In the deserializing method I get a temporary object, which I want to copy to an other new SerializeableObject, wich I want to use after, but I can't copy it properly, however the temporary object got the values properly, at the deserialization. Here's my classes:
SeralizeableObject:
public class SerializableObject implements Serializable, Cloneable{
private Vector<int[]> mixMade;
private Vector<int[]> stepsMade;
private long time;
private int steps;
private int winnerState;
public SerializableObject(Vector<int[]> mixMade, Vector<int[]> stepsMade,
long time, int steps, int winnerState) {
this.mixMade = mixMade;
this.stepsMade = stepsMade;
this.time = time;
this.steps = steps;
this.winnerState = winnerState;
}
#Override
public String toString() {
String str = "";
for(int[] mixEl : mixMade){
str += mixEl[0] + ", " + mixEl[1] + "|";
}
str += " mixes\n";
for(int[] stepEl : stepsMade){
str += stepEl[0] + ", " + stepEl[1] + "|";
}
str += " steps\n";
str += "time: " + time + ", stepsnum: " + steps + ",
winstate: " + winnerState;
return str;
}
#Override
public SerializableObject clone() {
SerializableObject serObj;
Vector<int[]> mixMadeTemp = new Vector<int[]>();
Vector<int[]> stepsMadeTemp = new Vector<int[]>();
for(int i = 0; i < mixMade.size(); ++i){
mixMadeTemp.add(mixMade.get(i));
}
for(int i = 0; i < stepsMade.size(); ++i){
stepsMadeTemp.add(stepsMade.get(i));
}
serObj = new SerializableObject(mixMadeTemp, stepsMadeTemp,
time, steps, winnerstate);
return serObj;
}
}
The Serializator:
public class ObjectSerializator {
public ObjectSerializator() {
}
public void toFile(String filepath, SerializableObject serObj){
ObjectOutputStream out;
try{
FileOutputStream fileOut = new FileOutputStream(filepath);
out = new ObjectOutputStream(fileOut);
out.writeObject(serObj);
}catch (IOException ex) {
}
}
public void fromFile(String filepath, SerializableObject serObj){
SerializableObject tempSerObj;
try {
FileInputStream fileIn = new FileInputStream(filepath);
ObjectInputStream in = new ObjectInputStream(fileIn);
tempSerObj = (SerializableObject) in.readObject();
System.out.println(tempSerObj + "TEMP");
serObj = tempSerObj.clone();
in.close();
fileIn.close();
} catch (IOException ex) {
} catch (ClassNotFoundException ex) {
}
}
}
note: the serobj reference points properly to the good values, inside the fromFile method
A filechooser class, where the user can chhose the file to load from:
public class FileChooser extends JFileChooser{
private ObjectSerializator serializator;
public FileChooser() {
serializator = new ObjectSerializator();
}
public void load(SerializableObject serObj){
int retValue = showOpenDialog(null);
serializator.fromFile(getSelectedFile().getAbsolutePath(), serObj);
}}
than in my mainfram I call it from a buttonaction
public void load(){
SerializableObject serObj = new SerializableObject(new Vector<int[]>(), new
Vector<int[]>(), 10, 10, 200);
fileChooser.load(serObj);
System.out.println(serObj + " LAST");
}
Here's my output:
3, 2|4, 3| mixes
0, 0|0, 1|0, 0| steps
time: 6000, stepsnum: 3, winstate: 0TEMP
-------------------
mixes
steps
time: 10, stepsnum: 10, winstate: 200 LAST

The object you've deserialized gets lost.
In your fromFile method, you have the following line:
serObj = tempSerObj.clone();
But serObj is an argument to the method. The line above changes the local serObj variable, whereas the original object remains intact. The calling method (load) still holds a reference to the old (original) object.
Your fromFile method shouldn't accept a SerializableObject as an argument; rather, it should return one. Then the FileChooser.load method should return it as well. Finally, the load method of the main frame should look something like:
public void load() {
SerializableObject originalObject = new SerializableObject(new Vector<int[]>(), new Vector<int[]>(), 10, 10, 200);
// Here you can do something with the newly created object, such as save it to a file.
SerializableObject deserializedObject = fileChooser.load();
System.out.println(deserializedObject + " LAST");
}

Related

I'm having trouble setting the value of a variable that will update my test

My problem is in the part where I'm doing the "if/else" conditions, when I call the function that will perform the comparisons and will define if the test passed or not and will send some information, I'm receiving null.
Problems are among the asterisks. If anyone can help me
This is my code :
public static void fxSpot_GBP_JPY(TradeData data, TradeData output) throws Exception {
if (data == null) {
fail("The input data object was not correctly filled");
}
if (output == null) {
fail("The output data object was not correctly filled");
}
//Used to set the comment, the status and update to JIRA
FieldsJSON fields = new FieldsJSON();
String assertionError = "";
List<String> inputs = new ArrayList<String>();
List<String> outputs = new ArrayList<String>();
String newDate = Utils.formatTimeZoneMinute(data.getTradeDate());
String asOfTrade = Utils.formatTimeZoneMinute(data.getAsOfTradeDate());
String executionDate = Utils.formatTimeZoneMinute(output.getExecutionDateTime());
try {
//Add the data in the list
inputs.add(data.getTransactionNumber()); outputs.add(output.getBloombergId());
inputs.add(newDate); outputs.add(output.getTradeDate());
inputs.add(asOfTrade); outputs.add(executionDate);
inputs.add(data.getSettlementDate()); outputs.add(output.getValueDate());
inputs.add(data.getTradeAmount()); outputs.add(output.getAmount2());
inputs.add(data.getCustomerAccountCounterparty()); outputs.add(output.getMiPartyId());
inputs.add(data.getPrincipalLoanAmount()); outputs.add(output.getAmount());
inputs.add(data.getSecurityPrice()); outputs.add(output.getRate());
inputs.add(data.getISOCodeOf1stCurrency()); outputs.add("BRL");//output.getCurrency2()
inputs.add(data.getISOCodeOf2ndCurrency()); outputs.add(output.getCurrency1());
//Compare values
System.out.println("-------------------");
int y = 0;
int x = 0;
for(String input : inputs) {
for(String out : outputs) {
if(y == x) {
if(input.equals(out)) {
WriterCSV.setOk("Ok");
**String comment = input + " = " + out;
fields.setComment(comment);
fields.setStatus("PASS");**
System.out.println("ok - " + input + " = " + out);
}else {
WriterCSV.setOk("not Ok");
**String comment = input + " = " + out;
fields.setComment(comment);
fields.setStatus("FAIL");**
System.out.println("not Ok - " + input + " = " + out);
}
}
x = x+1; // count of the list of output
}
y = y+1; // count of the list of inputs
x = 0; // reset to 0 the count of outputs
}
// evidence with the name and value of fields compared
WriterCSV.reportSpot_CSV(data,output);
}
Here is my test:
#Test
#Tag("compare")
public void CompareSpot() throws Exception {
//Create a list to read the CSVfile
List<DTOTradeData> dto;
//Used to get the TradeData of list dto.
DTOTradeData dtd = new DTOTradeData();
// Read a csvFile and return a list with the values to new xml
dto = CSVReader.readCSV("spot.csv");
//The xpath of xml
FileDriverSpot spot = new FileDriverSpot();
FileDriver output = new FileDriverSpotOutput();
FieldsJSON fields = new FieldsJSON();
//new xml = dataInput and the outputFile = dataOutput
TradeData dataInput = new TradeData();
TradeData dataOutput = new TradeData();
for (int i = 0; i < dto.size(); i++) {
dtd = dto.get(i); // get TradeData
dtd.getTradeData().setDriver(spot); // set the driver
if (fileExist(Setup.xmlPath + dtd.getInputFile() + ".xml")) {
dataInput = Reader.read(spot, Setup.xmlPath + dtd.getInputFile() + ".xml");
dataOutput = Reader.read(output, Setup.spotPath + dtd.getOutputFile());
try {
// make the comparison
**FunctionalTest.fxSpot_GBP_JPY(dataInput, dataOutput);**
}
catch(AssertionError e) {
String comment = e.toString();
fields.setComment(comment);
}
} else {
fail("The file: " + dtd.getTemplateFile()
+ " needs to go through the writing process before being compared.");
}
//Convert the file to base64
String inputData = UpdateTestStatus.convertToBase64(Setup.xmlPath + dtd.getInputFile() + ".xml");
String outputData = UpdateTestStatus.convertToBase64(Setup.spotPath + dtd.getOutputFile());
String evidenceCompared = UpdateTestStatus.convertToBase64(Setup.reportPath+"ReportSpot.csv");
System.out.println(UpdateTestStatus.updateTestRun(**fields.getStatus(),fields.getComment()**,
inputData,dtd.getInputFile()+ ".xml", //data of the XML and the name of the file
outputData,dtd.getOutputFile(),
evidenceCompared,"ReportSpot.csv",
Setup.testExec, dtd.getJiraId()).asString()); // ID testExecution and ID of
}
}
The test and the code under test each create a separate instance of FieldsJSON. Data set in one instance will not be visible in the other (unless the data is declared static, in which case there's no need to create instances).
You can fix this by using a single instance, either passed to the fxSpot_GBP_JPY method from the test, or returned from that method to the test.

TreeMap with (String,ArrayList<String,Int>)

I am trying to read an input file. Each value of the input file is inserted into the TreeMap as
If word is not existing: Insert the word to the treemap and associate the word with an ArrayList(docId, Count).
If the Word is present in the TreeMap, then check if the current DocID matches within the ArrayList and then increase the count.
THe
For the ArrayList, I created another class as below:
public class CountPerDocument
{
private final String documentId;
private final int count;
CountPerDocument(String documentId, int count)
{
this.documentId = documentId;
this.count = count;
}
public String getDocumentId()
{
return this.documentId;
}
public int getCount()
{
return this.count;
}
}
After that, I am trying to print the TreeMap into a text file as <DocID - Count>
Not sure what I am doing wrong here, but the output I get is as follows:
The Stem is todai:[CountPerDocument#5caf905d, CountPerDocument#27716f4, CountPerDocument#8efb846, CountPerDocument#2a84aee7, CountPerDocument#a09ee92, CountPerDocument#30f39991]
Wondering if anyone can guide me what i am doing wrong and if my method isn't correct what am i supposed to do?
public class StemTreeMap
{
private static final String r1 = "\\$DOC";
private static final String r2 = "\\$TITLE";
private static final String r3 = "\\$TEXT";
private static Pattern p1,p2,p3;
private static Matcher m1,m2,m3;
public static void main(String[] args)
{
BufferedReader rd,rd1;
String docid = null;
String id;
int tf = 0;
//CountPerDocument cp = new CountPerDocument(docid, count);
List<CountPerDocument> ls = new ArrayList<>();
Map<String,List<CountPerDocument>> mp = new TreeMap<>();
try
{
rd = new BufferedReader(new FileReader(args[0]));
rd1= new BufferedReader(new FileReader(args[0]));
int docCount = 0;
String line = rd.readLine();
p1 = Pattern.compile(r1);
p2 = Pattern.compile(r2);
p3 = Pattern.compile(r3);
while(line != null)
{
m1 = p1.matcher(line);
m2 = p2.matcher(line);
m3 = p3.matcher(line);
if(m1.find())
{
docid = line.substring(5, line.length());
docCount++;
//System.out.println("The Document ID is :");
//System.out.println(docid);
line = rd.readLine();
}
if(m2.find()||m3.find())
{
line = rd.readLine();
}
else
{
if(!(mp.containsKey(line))) // if the stem is not on the TreeMap
{
//System.out.println("The stem is not present in the tree");
tf = 1;
ls.add(new CountPerDocument(docid,tf));
mp.put(line, ls);
line = rd.readLine();
}
else
{
if(ls.indexOf(docid) > 0) //if its last entry matches the current document number
{
//System.out.println("The Stem is present for the same docid so incrementing docid");
tf = tf+1;
ls.add(new CountPerDocument(docid,tf));
line = rd.readLine();
}
else
{
//System.out.println("Stem is present but not the same docid so inserting new docid");
tf = 1;
ls.add(new CountPerDocument(docid,tf)); //set did to the current document number and tf to 1
line = rd.readLine();
}
}
}
}
rd.close();
System.out.println("The Number of Documents in the file is:"+ docCount);
//Write to an output file
String l = rd1.readLine();
File f = new File("dictionary.txt");
if (f.createNewFile())
{
System.out.println("File created: " + f.getName());
}
else
{
System.out.println("File already exists.");
Path path = Paths.get("dictionary.txt");
Files.deleteIfExists(path);
System.out.println("Deleted Existing File:: Creating New File");
f.createNewFile();
}
FileWriter fw = new FileWriter("dictionary.txt");
fw.write("The Total Number of Stems: " + mp.size() +"\n");
fw.close();
System.out.println("The Stem is todai:" + mp.get("todai"));
}catch(IOException e)
{
e.printStackTrace();
}
}
}
You didn't define the function String toString() in your class CountPerDocument. So, when you try to print a CountPerDocument variable, the default printed value is CountPerDocument#hashcode.
To decide how to represent a CountPerDocument variable in your code, add in your class the next function:
#Override
public String toString() {
return "<" + this.getDocumentId() + ", " + this.getCount() + ">";
}
Try to override toString method in CountPerDocument. Something like this:
public class CountPerDocument
{
private final String documentId;
private final int count;
CountPerDocument(String documentId, int count)
{
this.documentId = documentId;
this.count = count;
}
public String getDocumentId()
{
return this.documentId;
}
public int getCount()
{
return this.count;
}
#Override
public String toString() {
return documentId + "-" + count;
}
}

This code keeps formatting the file instead of writing to it. How do i fix it?

I have declared an array and and variables up here. productList array, name, price and number
import java.io.*;
import java.util.*;
public class ReadingAndWritting {
public String name;
public double price;
public int number;
public ReadingAndWritting[] productList = new ReadingAndWritting[3];
public ReadingAndWritting() {
}
public ReadingAndWritting(String name, double price, int number) {
this.name = name;
this.price = price;
this.number = number;
}
public void printContents() {
int i = 0;
try {
FileReader fl = new FileReader("Product List.txt");
Scanner scn = new Scanner(fl);
while (scn.hasNext()) {
String productName = scn.next();
double productPrice = scn.nextDouble();
int productAmount = scn.nextInt();
System.out.println(productName + " is " + productPrice + " pula. There are " + productAmount + " items left in stalk.");
productList[i] = new ReadingAndWritting(productName, productPrice, productAmount);
i = i + 1;
}
scn.close();
} catch (IOException exc) {
exc.printStackTrace();
} catch (Exception exc) {
exc.printStackTrace();
}
}
public void writeContents() {
try {
//FileOutputStream formater = new FileOutputStream("Product List.txt",true);
Formatter writer = new Formatter(new FileOutputStream("Product List.txt", true));
for (int i = 0; i < productList.length; ++i) {
writer.format(name, (price + 100.0), (number - 1), "\n");
}
writer.close();
} catch (IOException exc) {
exc.printStackTrace();
}
}
public static void main(String[] args) {
ReadingAndWritting obj = new ReadingAndWritting();
System.out.println("_____THIS IS THE BEGINNING OF THE PRODUCT LIST_____");
obj.printContents();
System.out.println("_____THIS IS THE END OF THE PRODUCT LIST_____");
System.out.println("_____THIS IS THE BEGINNING OF THE PRODUCT LIST_____");
obj.writeContents();
obj.printContents();
System.out.println("_____THIS IS THE END OF THE PRODUCT LIST_____");
}
}
Every time i run the code it keeps formatting the existing file and then reporting a NullPointerException. I am completely lost as to how to fix this and our lecturer never covered it. Please
the productList[] array has name,price and number value contained in each identifier. I want to wipe the contents of the existing file and then write with the new values to update contents from the array
The constructor you are using truncates the input file, as clearly stated in the Javadoc :
fileName The name of the file to use as the destination of this formatter. If the file exists then it will be truncated to zero size; otherwise, a new file will be created. The output will be written to the file and is buffered.
You can use other constructors, such as Formatter(OutputStream os) to avoid that truncation.
Formatter writer = new Formatter(new FileOutputStream("Product List.txt",true));
As for the NullPointerException, seeing your comment of :
public String name;
name is not initialized, so it is null by default, which leads to the NullPointerException.
P.S. I don't know what productList is, by based on its name and the fact that you are iterating over it, perhaps you should get the price and name from the elements of that list.
EDIT :
Based on the rest of your code, you should take the values from the productList array :
for (int i = 0; i < productList.length; ++i) {
writer.format(productList[i].name, (productList[i].price + 100.0), (productList[i].number - 1), "\n");
}
writer.format(name, (price + 100.0), (number - 1), "\n");
has the incorrect parameters. Due to which its giving the NullPointerException.
Read the Java doc to know about the correct parameters that should be passed.
Do something like this:
public String str=null; //declare class variable str.
In the printContents() method assign the following to the string:
str = "\n"+productName +" "+ (productPrice + 100.0)+" "+ (productAmount - 1)+"\n";
And then finally method, change the parameters being passed to writer.format() method like this:
Formatter writer = new Formatter(new FileOutputStream("Product List.txt", true));
for (int i = 0; i < productList.length; ++i) {
writer.format(str);
}
This is working for me.
The value you want is getting properly appended in the file "ProductList.txt".

Is a static method containing loops thread-safe?

I have a huge loop that I wanted to split up into 4 threads. I've done so using a little bit noobish method(or maybe not?) and split up the counter of the for loops into 4 intervals, created a new Printwriter, and CrucibleOptimizer for each thread so that there are no conflicts, like this:
public static void main(String[] args) {
Runnable run1 = new Runnable() {
#Override
public void run() {
PrintWriter writer1;
try {
writer1 = new PrintWriter("test_result1.txt");
CrucibleOptimizer optimizer1 = new CrucibleOptimizer();
int[] loop1boundries = new int[]{1, 7};
opt(optimizer1, writer1, loop1boundries[0], loop1boundries[1]);
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
}
}
};
Runnable run2 = new Runnable() {
#Override
public void run() {
PrintWriter writer2;
try {
writer2 = new PrintWriter("test_result2.txt");
CrucibleOptimizer optimizer2 = new CrucibleOptimizer();
int[] loop2boundries = new int[]{8, 14};
opt(optimizer2, writer2, loop2boundries[0], loop2boundries[1]);
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
}
}
};
Runnable run3 = new Runnable() {
#Override
public void run() {
PrintWriter writer3;
try {
writer3 = new PrintWriter("test_result3.txt");
CrucibleOptimizer optimizer3 = new CrucibleOptimizer();
int[] loop3boundries = new int[]{15, 22};
opt(optimizer3, writer3, loop3boundries[0], loop3boundries[1]);
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
}
}
};
Runnable run4 = new Runnable() {
#Override
public void run() {
PrintWriter writer4;
try {
writer4 = new PrintWriter("test_result4.txt");
CrucibleOptimizer optimizer4 = new CrucibleOptimizer();
int[] loop4boundries = new int[]{23, 30};
opt(optimizer4, writer4, loop4boundries[0], loop4boundries[1]);
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
}
}
};
Thread[] threads = new Thread[]{new Thread(run1), new Thread(run2), new Thread(run3), new Thread(run4)};
for (Thread thr : threads){
thr.start();
}
}
And this is the method that I'm asking about. I don't know if its thread safe. I've been reading around and google says that as far as I don't have any local variables, I'm fine, but what concerns me is the multiple counters in those loops:
public static void opt(CrucibleOptimizer opt, PrintWriter writer, int minIncluded, int maxIncluded){
//more than this is never used
final int oreMaterialsMaximum = 100;//100
final int ingotMaterialMaximum = 30;//30
//test for every possible material combination
for (int a = minIncluded; a <= maxIncluded; a++){//for amount of ingots
System.out.println("Testing for ingot number: " + a);
double ratioMin = (Reference.UNITS_IMPOSSIBLE / (double)(a * Reference.UNITS_INGOT));
for (int i = 0; i <= (int)(100 / Reference.UNITS_IMPOSSIBLE); i++){//for every ratio possible
double currentRatio = round(i * ratioMin, 6);
System.out.println("Testing for ratio: " + currentRatio);
for (int b = 0; b <= ingotMaterialMaximum; b++){//with every amount of ingots
for (int c = 0; c <= oreMaterialsMaximum; c++){//with every amount of rich ore
for (int d = 0; d <= oreMaterialsMaximum; d++){//with every amount of normal ore
for (int e = 0; e <= oreMaterialsMaximum; e++){//with every amount of poor ore
for (int f = 0; f <= oreMaterialsMaximum; f++){//with every amount of small ore
opt.set(null, null, null, a); //only the ingots are passed in this way
int[] res = opt.optimizeMaterial(new int[]{c, d, e, f, b}, currentRatio);
if (res != null){
int units = 0;
for (int j = 0; j < res.length; j++)
units += res[j] * Reference.MATERIAL_UNITS[j];
double unitsRight = Math.round(a * Reference.UNITS_INGOT * currentRatio);
if (units != (int)unitsRight){ //if the units are not correct, log
writer.println("I: " + a + " Rat: " + currentRatio + " I_av: " + b + " O_Ri: " + c + " O_No: " + d +
" O_Po: " + e + " O_Sm: " + f + " units_wrong: " + units + " units_right: " + (int)unitsRight);
}
}
}
}
}
}
}
}
}
System.out.println("Testing done");
writer.close();
}
The "do not use static variables" advise is indeed too simplistic: the other requirement is to not pass shared objects to static methods running in different threads.
Loop counters and other primitive local variables are thread-safe. The only thing that could make a method non-thread safe is shared state. It appears that you have successfully avoided that by creating separate CrucibleOptimizer and PrintWriter objects.
One refactoring that I would attempt is combining your Runnables. Make a named class that takes loop boundaries, and make four instances of that class in your main. This would work better than four separate anonymous classes that have very few differences:
private static class ThreadRunnable implements Runnable {
final String fileName;
final int[] loopBoundaries;
public ThreadRunnable(String fn, int[] lb) {
fileName = fn;
loopBoundaries = lb;
}
#Override
public void run() {
PrintWriter pw;
try {
pw = new PrintWriter(fileName);
CrucibleOptimizer co = new CrucibleOptimizer();
opt(co, pw, loop4boundries[0], loop4boundries[1]);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Now you can make four ThreadRunnable instances which share identical code.
Loops in of themselves are thread safe, so no you don't need to worry about that.
The only thing you need to worry about is anything that might be accessed by multiple threads at once.
However your entire architecture really needs some work.
For example why have 4 separate implementations for the runables rather than having one implementation and passing parameters into it to say which chunk to work on.
I also don't know what you are trying to do with all the loops but it's highly unlikely you really need any structure like that.

How to discover a File's creation time with Java?

Is there an easy way to discover a File's creation time with Java? The File class only has a method to get the "last modified" time. According to some resources I found on Google, the File class doesn't provide a getCreationTime() method because not all file systems support the idea of a creation time.
The only working solution I found involes shelling out the the command line and executing the "dir" command, which looks like it outputs the file's creation time. I guess this works, I only need to support Windows, but it seems very error prone to me.
Are there any third party libraries that provide the info I need?
Update: In the end, I don't think it's worth it for me to buy the third party library, but their API does seem pretty good so it's probably a good choice for anyone else that has this problem.
With the release of Java 7 there is a built-in way to do this:
Path path = Paths.get("path/to/file");
BasicFileAttributes attributes = Files.readAttributes(path, BasicFileAttributes.class);
FileTime creationTime = attributes.creationTime();
It is important to note that not all operating systems provide this information. I believe in those instances this returns the mtime which is the last modified time.
Windows does provide creation time.
I've wrote a small test class some days ago, wish it can help you:
// Get/Set windows file CreationTime/LastWriteTime/LastAccessTime
// Test with jna-3.2.7
// [http://maclife.net/wiki/index.php?title=Java_get_and_set_windows_system_file_creation_time_via_JNA_(Java_Native_Access)][1]
import java.io.*;
import java.nio.*;
import java.util.Date;
// Java Native Access library: jna.dev.java.net
import com.sun.jna.*;
import com.sun.jna.ptr.*;
import com.sun.jna.win32.*;
import com.sun.jna.platform.win32.*;
public class WindowsFileTime
{
public static final int GENERIC_READ = 0x80000000;
//public static final int GENERIC_WRITE = 0x40000000; // defined in com.sun.jna.platform.win32.WinNT
public static final int GENERIC_EXECUTE = 0x20000000;
public static final int GENERIC_ALL = 0x10000000;
// defined in com.sun.jna.platform.win32.WinNT
//public static final int CREATE_NEW = 1;
//public static final int CREATE_ALWAYS = 2;
//public static final int OPEN_EXISTING = 3;
//public static final int OPEN_ALWAYS = 4;
//public static final int TRUNCATE_EXISTING = 5;
public interface MoreKernel32 extends Kernel32
{
static final MoreKernel32 instance = (MoreKernel32)Native.loadLibrary ("kernel32", MoreKernel32.class, W32APIOptions.DEFAULT_OPTIONS);
boolean GetFileTime (WinNT.HANDLE hFile, WinBase.FILETIME lpCreationTime, WinBase.FILETIME lpLastAccessTime, WinBase.FILETIME lpLastWriteTime);
boolean SetFileTime (WinNT.HANDLE hFile, final WinBase.FILETIME lpCreationTime, final WinBase.FILETIME lpLastAccessTime, final WinBase.FILETIME lpLastWriteTime);
}
static MoreKernel32 win32 = MoreKernel32.instance;
//static Kernel32 _win32 = (Kernel32)win32;
static WinBase.FILETIME _creationTime = new WinBase.FILETIME ();
static WinBase.FILETIME _lastWriteTime = new WinBase.FILETIME ();
static WinBase.FILETIME _lastAccessTime = new WinBase.FILETIME ();
static boolean GetFileTime (String sFileName, Date creationTime, Date lastWriteTime, Date lastAccessTime)
{
WinNT.HANDLE hFile = OpenFile (sFileName, GENERIC_READ); // may be WinNT.GENERIC_READ in future jna version.
if (hFile == WinBase.INVALID_HANDLE_VALUE) return false;
boolean rc = win32.GetFileTime (hFile, _creationTime, _lastAccessTime, _lastWriteTime);
if (rc)
{
if (creationTime != null) creationTime.setTime (_creationTime.toLong());
if (lastAccessTime != null) lastAccessTime.setTime (_lastAccessTime.toLong());
if (lastWriteTime != null) lastWriteTime.setTime (_lastWriteTime.toLong());
}
else
{
int iLastError = win32.GetLastError();
System.out.print ("获取文件时间失败,错误码:" + iLastError + " " + GetWindowsSystemErrorMessage (iLastError));
}
win32.CloseHandle (hFile);
return rc;
}
static boolean SetFileTime (String sFileName, final Date creationTime, final Date lastWriteTime, final Date lastAccessTime)
{
WinNT.HANDLE hFile = OpenFile (sFileName, WinNT.GENERIC_WRITE);
if (hFile == WinBase.INVALID_HANDLE_VALUE) return false;
ConvertDateToFILETIME (creationTime, _creationTime);
ConvertDateToFILETIME (lastWriteTime, _lastWriteTime);
ConvertDateToFILETIME (lastAccessTime, _lastAccessTime);
//System.out.println ("creationTime: " + creationTime);
//System.out.println ("lastWriteTime: " + lastWriteTime);
//System.out.println ("lastAccessTime: " + lastAccessTime);
//System.out.println ("_creationTime: " + _creationTime);
//System.out.println ("_lastWriteTime: " + _lastWriteTime);
//System.out.println ("_lastAccessTime: " + _lastAccessTime);
boolean rc = win32.SetFileTime (hFile, creationTime==null?null:_creationTime, lastAccessTime==null?null:_lastAccessTime, lastWriteTime==null?null:_lastWriteTime);
if (! rc)
{
int iLastError = win32.GetLastError();
System.out.print ("设置文件时间失败,错误码:" + iLastError + " " + GetWindowsSystemErrorMessage (iLastError));
}
win32.CloseHandle (hFile);
return rc;
}
static void ConvertDateToFILETIME (Date date, WinBase.FILETIME ft)
{
if (ft != null)
{
long iFileTime = 0;
if (date != null)
{
iFileTime = WinBase.FILETIME.dateToFileTime (date);
ft.dwHighDateTime = (int)((iFileTime >> 32) & 0xFFFFFFFFL);
ft.dwLowDateTime = (int)(iFileTime & 0xFFFFFFFFL);
}
else
{
ft.dwHighDateTime = 0;
ft.dwLowDateTime = 0;
}
}
}
static WinNT.HANDLE OpenFile (String sFileName, int dwDesiredAccess)
{
WinNT.HANDLE hFile = win32.CreateFile (
sFileName,
dwDesiredAccess,
0,
null,
WinNT.OPEN_EXISTING,
0,
null
);
if (hFile == WinBase.INVALID_HANDLE_VALUE)
{
int iLastError = win32.GetLastError();
System.out.print (" 打开文件失败,错误码:" + iLastError + " " + GetWindowsSystemErrorMessage (iLastError));
}
return hFile;
}
static String GetWindowsSystemErrorMessage (int iError)
{
char[] buf = new char[255];
CharBuffer bb = CharBuffer.wrap (buf);
//bb.clear ();
//PointerByReference pMsgBuf = new PointerByReference ();
int iChar = win32.FormatMessage (
WinBase.FORMAT_MESSAGE_FROM_SYSTEM
//| WinBase.FORMAT_MESSAGE_IGNORE_INSERTS
//|WinBase.FORMAT_MESSAGE_ALLOCATE_BUFFER
,
null,
iError,
0x0804,
bb, buf.length,
//pMsgBuf, 0,
null
);
//for (int i=0; i<iChar; i++)
//{
// System.out.print (" ");
// System.out.print (String.format("%02X", buf[i]&0xFFFF));
//}
bb.limit (iChar);
//System.out.print (bb);
//System.out.print (pMsgBuf.getValue().getString(0));
//win32.LocalFree (pMsgBuf.getValue());
return bb.toString ();
}
public static void main (String[] args) throws Exception
{
if (args.length == 0)
{
System.out.println ("获取 Windows 的文件时间(创建时间、最后修改时间、最后访问时间)");
System.out.println ("用法:");
System.out.println (" java -cp .;..;jna.jar;platform.jar WindowsFileTime [文件名1] [文件名2]...");
return;
}
boolean rc;
java.sql.Timestamp ct = new java.sql.Timestamp(0);
java.sql.Timestamp wt = new java.sql.Timestamp(0);
java.sql.Timestamp at = new java.sql.Timestamp(0);
for (String sFileName : args)
{
System.out.println ("文件 " + sFileName);
rc = GetFileTime (sFileName, ct, wt, at);
if (rc)
{
System.out.println (" 创建时间:" + ct);
System.out.println (" 修改时间:" + wt);
System.out.println (" 访问时间:" + at);
}
else
{
//System.out.println ("GetFileTime 失败");
}
//wt.setTime (System.currentTimeMillis());
wt = java.sql.Timestamp.valueOf("2010-07-23 00:00:00");
rc = SetFileTime (sFileName, null, wt, null);
if (rc)
{
System.out.println ("SetFileTime (最后修改时间) 成功");
}
else
{
//System.out.println ("SetFileTime 失败");
}
}
}
}
I've been investigating this myself, but I need something that will work across Windows/*nix platforms.
One SO post includes some links to Posix JNI implementations.
JNA-POSIX
POSIX for Java
In particular, JNA-POSIX implements methods for getting file stats with implementations for Windows, BSD, Solaris, Linux and OSX.
All in all it looks very promising, so I'll be trying it out on my own project very soon.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class CreateDateInJava {
public static void main(String args[]) {
try {
// get runtime environment and execute child process
Runtime systemShell = Runtime.getRuntime();
BufferedReader br1 = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter filename: ");
String fname = (String) br1.readLine();
Process output = systemShell.exec("cmd /c dir \"" + fname + "\" /tc");
System.out.println(output);
// open reader to get output from process
BufferedReader br = new BufferedReader(new InputStreamReader(output.getInputStream()));
String out = "";
String line = null;
int step = 1;
while ((line = br.readLine()) != null) {
if (step == 6) {
out = line;
}
step++;
}
// display process output
try {
out = out.replaceAll(" ", "");
System.out.println("CreationDate: " + out.substring(0, 10));
System.out.println("CreationTime: " + out.substring(10, 16) + "m");
} catch (StringIndexOutOfBoundsException se) {
System.out.println("File not found");
}
} catch (IOException ioe) {
System.err.println(ioe);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
/**
D:\Foldername\Filename.Extension
Ex:
Enter Filename :
D:\Kamal\Test.txt
CreationDate: 02/14/2011
CreationTime: 12:59Pm
*/
The javaxt-core library includes a File class that can be used to retrieve file attributes, including the creation time. Example:
javaxt.io.File file = new javaxt.io.File("/temp/file.txt");
System.out.println("Created: " + file.getCreationTime());
System.out.println("Accessed: " + file.getLastAccessTime());
System.out.println("Modified: " + file.getLastModifiedTime());
Works with Java 1.5 and up.
I like the answer on jGuru that lists the option of using JNI to get the answer. This might prove to be faster than shelling out and you may encounter other situations such as this that need to be implemented specifically for windows.
Also, if you ever need to port to a different platform, then you can port your library as well and just have it return -1 for the answer to this question on *ix.
This is a basic example in Java, using BasicFileAttributes class:
Path path = Paths.get("C:\\Users\\jorgesys\\workspaceJava\\myfile.txt");
BasicFileAttributes attr;
try {
attr = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("File creation time: " + attr.creationTime());
} catch (IOException e) {
System.out.println("oops un error! " + e.getMessage());
}

Categories

Resources