Opening files in a parallel loop crash the program - file

I'm making a simple program in D that loops around the files present inside a given folder and calculate the MD5 of the file. I have got this program working easily with no problem.
I recently learned more about parallelism and thought that my little program would benefit greatly from it.
I changed the loop around the files to a parallel one, but now it is working weird.
The program starts reading files and calculating their MD5, but sometimes, executing close(file) throw an exception with error code 0. Sometimes, there is just an
Object.Error: Access violation
Sometimes the program just freezes, sometimes it simply crashes.
When I remove the file opening (the loop then basically just print the filename to the console) it works well.
The time it takes for the program to crash is maybe linked to the size of workUnitSize. If not set (default 100), it crashes or stop working after processing around 30-40 files. If I set it to 1, it stops after 2 to 10 files.
Here is the smallest reproducible code I've extracted :
import std.md5;
import std.stdio;
import std.file;
import std.conv;
import std.getopt;
import std.string;
import std.process;
import std.parallelism;
import std.exception;
struct Entry
{
string name;
ubyte[16] md5;
}
int ChunkStep = 4096;
void main(string[] args)
{
string folder1 = args[1];
string folder2 = args[2];
Entry[] entries1;
foreach (name; parallel(dirEntries(folder1, SpanMode.breadth), 1)) // not working
{
if(name.isFile())
{
entries1 ~= Entry(name ,mdFile(name));
}
}
writeln(folder1," has ",entries1.length, " entries");
Entry[] entries2;
foreach (string name; dirEntries(folder2, SpanMode.breadth)) //working fine
{
if(name.isFile())
{
entries2 ~= Entry(name ,mdFile(name));
}
}
writeln(folder2," has ", entries2.length, " entries");
}
/// Digests a file and prints the result.
ubyte[16] mdFile(string filename)
{
MD5_CTX context;
ubyte[16] digest;
context.start();
File f = File(filename,"r");
foreach (buffer; f.byChunk(ChunkStep))
context.update(buffer);
context.finish(digest);
try{
f.close();
}
catch(ErrnoException e)
{
writeln(e.errno);
}
writefln("MD5 (%s) = %s", filename, digestToString(digest));
return digest;
}
I'm using Dmd2.064.2 on Windows 7 64b with a Intel Q6600 (quad core).

Do you use 32bit version of dmd?
update:
seems on windows there is some bug with byChunk (rawRead). So you can use std.stream instead.
import std.md5;
import std.stdio;
import std.file;
import std.conv;
import std.getopt;
import std.string;
static import std.stream;
import std.process;
import std.parallelism;
import std.exception;
struct Entry
{
string name;
ubyte[16] md5;
}
enum ChunkStep = 4096;
void main(string[] args)
{
string folder1 = args[1];
string folder2 = args[2];
Entry[] entries1;
foreach (name; parallel(dirEntries(folder1, SpanMode.breadth), 1)) // not working
{
if(name.isFile())
{
entries1 ~= Entry(name ,mdFile(name));
}
}
writeln(folder1," has ",entries1.length, " entries");
}
/// Digests a file and prints the result.
ubyte[16] mdFile(string filename)
{
MD5_CTX context;
ubyte[16] digest;
context.start();
std.stream.File f = new std.stream.File(filename);
byte[ChunkStep] buffer;
size_t len;
while((len = f.readBlock(buffer.ptr, ChunkStep)) > 0) {
context.update(buffer.ptr[0 .. len]);
}
context.finish(digest);
f.close();
writefln("MD5 (%s) = %s", filename, digestToString(digest));
return digest;
}

Related

How to protect my SQLite db by intentionally corrupting it, then fix it through code?

This is my first app on Android with Java and SQLite.
ISSUE:
I have a local SQLIte db on my app. I was very surprised to see how easy it is to get access to the db once you have installed the app (no need to be a programmer nor a hacker).
I tried adding SQLCipher to my app but it only worked for newer Android versions 11 & 12 and didn't work for Android 9 for example and it did make my app's size much bigger.
After researching more I found a better solution for my case which doesn"t involve crypting the db with SQLCipher but rather it consists of corrupting the first bytes of the db file then after each launch of the app the code will decorrupt the file and use the fixed file instead. This insures that anyone who decompiles the apk will only get access to a corrupt db file and will have to put more effort to fix it which is my goal.
I came across this solution in a reply [here][1] but I don't know how to implement it as I am new to Android and SQLite programming. Any help is much appreciated on how to actually do it.
These are the steps as mentioned by the user: farhad.kargaran which need more explanation as I don't get how to do it:
1- corrupt the db file (convert it to byte array and change some values)
2- copy it in asset folder
3- in first run fix corrupted file from asset and copy it in database
folder.
Change first 200 byte values like this:
int index = 0;
for(int i=0;i<100;i++)
{
byte tmp = b[index];
b[index] = b[index + 1];
b[index + 1] = tmp;
index += 2;
}
As only the first 200 bytes were replaced, the same code is used for fixing first 200 byte values.
Here is my code for the SQLiteOpenHelper if needed:
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = DatabaseHelper.class.getSimpleName();
public static String DB_PATH;
public static String DB_NAME;
public SQLiteDatabase database;
public final Context context;
public SQLiteDatabase getDb() {
return database;
}
public DatabaseHelper(Context context, String databaseName, int db_version) {
super(context, databaseName, null, db_version);
this.context = context;
DB_PATH = getReadableDatabase().getPath();
DB_NAME = databaseName;
openDataBase();
// prepare if need to upgrade
int cur_version = database.getVersion();
if (cur_version == 0) database.setVersion(1);
Log.d(TAG, "DB version : " + db_version);
if (cur_version < db_version) {
try {
copyDataBase();
Log.d(TAG, "Upgrade DB from v." + cur_version + " to v." + db_version);
database.setVersion(db_version);
} catch (IOException e) {
Log.d(TAG, "Upgrade error");
throw new Error("Error upgrade database!");
}
}
}
public void createDataBase() {
boolean dbExist = checkDataBase();
if (!dbExist) {
this.getReadableDatabase();
this.close();
try {
copyDataBase();
} catch (IOException e) {
Log.e(TAG, "Copying error");
throw new Error("Error copying database!");
}
} else {
Log.i(this.getClass().toString(), "Database already exists");
}
}
private boolean checkDataBase() {
SQLiteDatabase checkDb = null;
try {
String path = DB_PATH + DB_NAME;
checkDb = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
} catch (SQLException e) {
Log.e(TAG, "Error while checking db");
}
if (checkDb != null) {
checkDb.close();
}
return checkDb != null;
}
private void copyDataBase() throws IOException {
InputStream externalDbStream = context.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream localDbStream = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = externalDbStream.read(buffer)) > 0) {
localDbStream.write(buffer, 0, bytesRead);
}
localDbStream.close();
externalDbStream.close();
}
public SQLiteDatabase openDataBase() throws SQLException {
String path = DB_PATH + DB_NAME;
if (database == null) {
createDataBase();
database = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READWRITE);
}
return database;
}
#Override
public synchronized void close() {
if (database != null) {
database.close();
}
super.close();
}
Much appreciated.
[1]: https://stackoverflow.com/a/63637685/18684673
As part of the copyDatabase, correct and then write the corrupted data, then copy the rest.
Could be done various ways
e.g.
long buffersRead = 0; //<<<<< ADDED for detecting first buffer
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = externalDbStream.read(buffer)) > 0) {
if (bufferesRead++ < 1) {
//correct the first 200 bytes here before writing ....
}
localDbStream.write(buffer, 0, bytesRead);
}

NPC not moving to the target location

I am using citizensAPI to spawn and manipulate NPC. The code is as follows.
I am trying to find the nearest block of type JUNGLE_WOOD in the radius of 20.
package org.mineacademy.orion.npctest;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.ai.PathStrategy;
import net.citizensnpcs.api.hpastar.Tile;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.ai.AStarNavigationStrategy;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.mineacademy.fo.command.SimpleCommand;
public class BlockFinder extends SimpleCommand {
public BlockFinder(){
super("finder");
}
public void onCommand() {
checkConsole();
NPC npc= CitizensAPI.getNPCRegistry().createNPC(EntityType.VILLAGER,"cutter");
Player player=getPlayer();
npc.spawn(player.getTargetBlock(null, 5).getLocation().add(3, 3, 0));
//add location and setTarget to that location.
Location finalLoc=newLocation(npc,player);
npc.setProtected(false);
npc.faceLocation(finalLoc);
npc.getNavigator().setTarget(finalLoc);
}
public Location newLocation(NPC npc, Player player) {
double r =25;
double x=npc.getEntity().getLocation().getX();
double y=npc.getEntity().getLocation().getY();
double z=npc.getEntity().getLocation().getZ();
int minx=(int)(x-r);
int miny=(int)(y-r);
int minz=(int)(z-r);
int maxx=(int)(x+r);
int maxy=(int)(y+r);
int maxz=(int)(z+r);
Location nloc=new Location(npc.getEntity().getWorld(),x,y,z);
for(int rx=minx;rx<=maxx;rx++) {
for (int ry = miny; ry <= maxy; ry++) {
for (int rz = minz; rz <= maxz; rz++) {
Block block = player.getWorld().getBlockAt(rx, ry, rz);
if (block.getType() == Material.JUNGLE_WOOD) {
nloc.setX(rx);
nloc.setY(ry);
nloc.setZ(rz);
return nloc;
}
}
}
}
return nloc;
}
}
The NPC spawns properly but sometimes it does not move at all, and otherwise it spins or just moves a couple of meters and stops.
Does anyone know any fix so that I am able to move the NPC along a path to that block?
First of all, you should check if the NPC exists : NPC.isSpawned() - boolean
Then, you should trigger this part after the NPCSpawnEvent (https://jd.citizensnpcs.co/net/citizensnpcs/api/event/NPCSpawnEvent.html) :
Location finalLoc=newLocation(npc,player);
npc.setProtected(false);
npc.faceLocation(finalLoc);
npc.getNavigator().setTarget(finalLoc);
By the way, you can google it : https://www.spigotmc.org/threads/citizens-api-problem-walking-npc.365712/
I found this, really useful.

How to fix method printing null for some iterations?

Write a program that shall calculate the vocabulary richness of a text in a file and the frequency of the most common word. The vocabulary richness is the number of words in the text divided by the number of distinct words. The frequency of a word is the number of times the word is mentioned in the text divided by the total number of words in the text.
Define and implement class WordCounter with two private fields String word and int count, constructor WordCounter(String word), and public methods String getName(), int getCount(), and void addToCounter().
Define and implement class Corpus (as in text corpus) with one private field ArrayList<WordCounter> words, constructor Corpus(BufferedReader infile), and public methods double getVocabularyRichness() and String getMostFrequentWord().
Implement a test program (as the public static void main method in Corpus) that reads all files in a specific folder, creates a Corpus object from each (previously opened) file, and saves the requested statistics into another file stats.csv. You can either create a new Corpus object for each file or define an ArrayList<Corpus> of the corpora.
Each line of the CSV file must consist of three fields separated by commas (but no spaces!): the file name, the vocabulary richness, and the most frequently used word. Run your program on all Shakespeare's plays. Submit the CSV file together with the Java file.
I wrote what I think is the correct implementation of the HW problem because it works properly for some of the text files, however only the words.get(i).getName() (I tested with words.get(i).getCount()) method will print a blank space for some of the files. I have tried everything, and can't seem to figure it out. Can you please give me a hint or some guidance as to how to fix this issue?
public class Corpus {
private ArrayList<WordCounter> words = new ArrayList <WordCounter>() ;
Corpus(BufferedReader infile){
String ln;
try {
while((ln = infile.readLine()) != null) {
for (String word : ln.toLowerCase().split("([,.\\s]+)")) {
int reference = 0;
for(int i = 0; i < words.size(); i++) {
if (word.equals(words.get(i).getName())) {
reference++;
words.get(i).addToCounter();
} }
if (reference==0) { words.add(new WordCounter(word)); }
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public double getVocabularyRichness() {
int word_count=0;
for(int i = 0; i < words.size(); i++) {
word_count=word_count+words.get(i).getCount();
}
return (double)word_count/(double)words.size();
}
public String getMostFrequentWord() {
String winner = "*AN ERROR OCCURRED*";
int max_count = 0;
for(int i = 0; i < words.size(); i++) {
if(words.get(i).getCount() > max_count){
max_count = words.get(i).getCount();
}
}
for(int i = 0; i < words.size(); i++) {
if(words.get(i).getCount() == max_count){
winner = words.get(i).getName();
}
}
//winner="Test " + String.valueOf(words.get(i).getName());;
//return String.valueOf(max_count);
return winner;
}
public static void main(String [] args) throws Exception{
BufferedWriter writer = null;
File folder_location = new File("/Users/joaquindelaguardia/Desktop/Shakespeare");
File[] file_array = folder_location.listFiles();
for(File iteration_file: file_array) {
FileReader current_file = new FileReader(iteration_file);
BufferedReader infile = new BufferedReader(current_file);
Corpus obj1 = new Corpus(infile);
String file_name = iteration_file.getName();
String frequent_word = obj1.getMostFrequentWord();
String vocabulary_richness = String.valueOf(obj1.getVocabularyRichness());
System.out.println(file_name);
System.out.println(frequent_word);
System.out.println(vocabulary_richness);
System.out.println("-----------------------------");
//FileWriter file_writer = new FileWriter("/Users/joaquindelaguardia/Desktop/stats.csv");
//writer = new BufferedWriter(file_writer);
//String output = file_name+", "+frequent_word+", "+vocabulary_richness + "\n";
//writer.append(output);
}
//writer.close();
}
}
public class WordCounter {
private String word;
private int count=1;
WordCounter(String word){
this.word=word;
}
public String getName() {
return word;
}
public int getCount() {
return count;
}
public void addToCounter() {
count++;
}
}
Im testing the information by printing before appending to file, and as you can see with the small fragment of the output included below, for some cases it prints the most common word (and) while in the second case it doesn't print anything.
shakespeare-lovers-62.txt
and
2.2409948542024014
shakespeare-julius-26.txt
6.413205537806177

Implementing arrays for a Palindrome program

I am working on creating a program that reads strings in from a data file calles "palindromes.txt" and which stores the strings in a one-dimensional array. The program is supposed to inspect each of the strings and detrmine whether or not each one is a pallindrome. It's supposed to show output on the screen and into a file called "output.txt".
The problem i'm having is that I can't figure out how to get the input/output correct and i'm not sure the best way to utilize the arrays.
Very new to this, please advise if you can. :)
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
public class Palindromes2
{
public static boolean isPalindrome(String dirtystr)
{
dirtystr = dirtystr.toLowerCase().replaceAll("[^a-zA-Z]+","");
int length = dirtystr.length(), middle = length / 2;
for (int x = 0; x < middle; x++)
if (dirtystr.charAt(x) != dirtystr.charAt(length - x - 1))
return false;
return true;
}
public static void main(String[] args) throws IOException
{
File inputFile = new File("output.txt");
try (Scanner scanner = new Scanner(inputFile))
{
while (scanner.hasNextLine())
{
String dirtystr = scanner.nextLine();
if (isPalindrome(dirtystr))
{
System.out.println(dirtystr + " IS a palindrome.");
}
else
{
System.out.println(dirtystr + " is NOT a palindrome.");
}
}
}
}
}

"File system error (1003)" opening BlackBerry file connection

I tried the example from "J2ME/Blackberry - how to read/write text file?". I want only the read functionality, the file I want to read is in CSV format as a .txt file placed in the /res/test.txt.
But I am having an issue with the FileConnection. I get the following error:
File system error (1003)
Any suggestions or advice on a better approach or as to how I can get this working?
public class FileDemo extends MainScreen {
public FileDemo() {
setTitle("My Page");
String str = readTextFile("file:///test.txt");
System.out.println("Contents of the file::::::: " + str);
}
public String readTextFile(String fName) {
String result = null;
FileConnection fconn = null;
DataInputStream is = null;
try {
fconn = (FileConnection) Connector.openInputStream(fName);
is = fconn.openDataInputStream();
byte[] data = IOUtilities.streamToBytes(is);
result = new String(data);
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
if (null != is)
is.close();
if (null != fconn)
fconn.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
return result;
}
}
try this
InputStream is = getClass().getResourceAsStream("/test.txt");
StringBuffer buff = new StringBuffer();
int ch;
try {
while ((ch = is.read()) != -1)
buff.append((char) ch);
} catch (Exception e) {
Log.Error(e, "Exception ");
}
String str = (buff.toString());
Same problem I also faced in my project. First check your simulator memory card is inserted or not. From simulator,
go to Options(Settings)-->Device-->Storage and Check the Memory card Storage.
If the memory card is not inserted, than it will show Media Card is not currently inserted in the device. So, you need to insert the memory card. From simulator menu bar, choose simulate-->Change SD Card...
You can add the SD card here. Than you try.
I think, This suggestion will help someone.

Resources