SSIS Flat File In Use By Another Process - file

I've got an SSIS package that is responsible for picking up and loading files to SQL tables, and then routing the files to various archive locations depending upon the content of the file. Prior to doing any loading, however, I have some scripts that check for various file-level errors, one of which is if the file is empty or not. I am using the following script to check if a file is empty:
Dts.Variables["blnEmptyFile"].Value = false;
Dts.Variables["User::strFileTimeStamp"].Value = "_" + DateTime.Now.ToString("yyyyMMdd") + "_" + DateTime.Now.ToString("hhmmss");
if (Dts.Variables["User::strFileRecordType"].Value.ToString() == "AF")
{
Dts.Variables["User::strFileOutToGeBBs"].Value = "AF_" + Dts.Variables["User::strCurrentFileIn"].Value.ToString().Substring(0, Dts.Variables["User::strCurrentFileIn"].Value.ToString().Length - 7) + Dts.Variables["User::strFileTimeStamp"].Value.ToString() + ".txt";
}
else if (Dts.Variables["User::strFileRecordType"].Value.ToString() == "AS")
{
Dts.Variables["User::strFileOutToGeBBs"].Value = "AS_" + Dts.Variables["User::strCurrentFileIn"].Value.ToString().Substring(0, Dts.Variables["User::strCurrentFileIn"].Value.ToString().Length - 7) + Dts.Variables["User::strFileTimeStamp"].Value.ToString() + ".txt";
}
else if (Dts.Variables["User::strFileRecordType"].Value.ToString() == "R")
{
Dts.Variables["User::strFileOutToGeBBs"].Value = "R_" + Dts.Variables["User::strCurrentFileIn"].Value.ToString().Substring(0, Dts.Variables["User::strCurrentFileIn"].Value.ToString().Length - 6) + Dts.Variables["User::strFileTimeStamp"].Value.ToString() + ".txt";
}
else
{
Dts.Variables["User::strFileOutToGeBBs"].Value = Dts.Variables["User::strCurrentFileIn"].Value.ToString().Substring(0, Dts.Variables["User::strCurrentFileIn"].Value.ToString().Length - 4) + Dts.Variables["User::strFileTimeStamp"].Value.ToString() + ".txt";
}
int nonDataRows = 1;
string ffConnection;
ffConnection = (string)(Dts.Connections["CDF_Format"].AcquireConnection(null) as string);
FileInfo flatFileInfo = new FileInfo(ffConnection);
long fileSize = flatFileInfo.Length;
if (fileSize > 0)
{
int lineCount = 0;
StreamReader fsFlatFile = new StreamReader(ffConnection);
while (!(fsFlatFile.EndOfStream))
{
Console.WriteLine(fsFlatFile.ReadLine());
lineCount += 1;
if (lineCount > nonDataRows)
{
Dts.Variables["User::blnEmptyFile"].Value = false;
break;
}
else
{
Dts.Variables["User::blnEmptyFile"].Value = true;
}
}
fsFlatFile.Close();
fsFlatFile = null;
}
else
{
Dts.Variables["User::blnEmptyFile"].Value = true;
}
Dts.TaskResult = (int)ScriptResults.Success;
After this script task, I check the blnEmptyFile variable, and if it is True, I send the empty file to a failed files folder location so that our end users can deal with it. And when I run this script inside the editor (VS 2017/2019), it runs to successful completion every single time. However, when this is run on the ETL servers, it intermittently fails with the following error:
2022-01-18 07:15:14.27 fst_ArchFailedFile:Error: An error occurred with the following error message: "The process cannot access the file because it is being used by another process.".
This only ever happens when a file is empty, and even then, it is only happening with a specific set of files that are empty. And it doesn't happen all the time; it is intermittent, and seems to want to happen on Monday (or, in the case of long weekends, Tuesday) mornings.
As you can see in the code, I am closing fsFlatFile, and I'm setting it to null. ffConnection is a string, so I can't close/kill it...although setting it to NULL has no effect either. I've tried setting a PAUSE, and that also has no effect/bearing on what is happening.
Anybody have any ideas why this would happen, and how I can resolve this? We aren't talking about Excel here (I've seen all of those posts on the internet), but simple TXT files that have only but a header and nothing else in them. Any help here would be keen.

StreamReader still has it. Try using a using block, everything inside is properly closed, disposed, etc:
using(StreamReader fsFlatFile = new StreamReader(ffConnection))
{
All the code you want to do while your stream is open.
}

Related

Downloads folder shared file write permissions problem

I am trying to get an offline backup function working on Android 12. It has worked for years on previous versions of Android, 6 & 8. It is required as the size of the backup can often exceed 25mb. I am using a Samsung A7 Lite for this testing to ensure Android 12 compliance. Essentially the function initially creates a backup folder in the downloads folder if it does not exist. It then writes a backup file to that folder. All goes well. I can repeat the function any number of times without there being a problem. It retains father and grandfather versions for security. However, if I try to use the same function where there are existing files the following day, I am presented with a java.io.FileNotFoundException, open failed EACCES (Permission denied). This whole situation appears very illogical, and does not appear to follow the documentation on accessing the downloads folder. If I manually delete the backup file from the previous day, the process succeeds, similarly if I delete the backup directory within the downloads folder, the backup proceeds successfully. The app asks the user for the appropriate permissions which I believe are read and write external storage. Can anybody identify what I am doing wrong in this environment.
The code is below.
String path = "";
// if no external, set to download
if (path.equals("")) {
File systemPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
path = systemPath.getAbsolutePath();
}
// set up backup subdirectory
path = path + "/backup";
// check if path exists
File backupDir = new File(path);
if (!backupDir.exists()) {
try {
backupDir.mkdirs();
MediaScannerConnection.scanFile(this, new String[]{backupDir.getAbsolutePath()}, null, null);
}
catch(Exception e){
e.printStackTrace();
}
}
// first get rid of old backup files leaving at least 2 older versions
File backupFile = new File(path,"backup3.bkp");
if (backupFile.exists())
backupFile.delete();
for (int i = 3;i > 1;i--){
File renameBackupFile = new File(path,"backup" + i + ".bkp");
File existBackupFile = null;
if (i == 2)
existBackupFile = new File(path,"backup.bkp");
else
existBackupFile = new File(path,"backup" + (i - 1) + ".bkp");
if (existBackupFile.exists()) {
try {
existBackupFile.renameTo(renameBackupFile);
} catch (Exception e) {
String message = e.toString();
}
}
}
// create a new backup
String fileName = "backup.bkp";
String backup = path + "/" + fileName;
FileInputStream dataBaseFile = new FileInputStream(DB_PATH);
File newBackupFile = new File(backup);
newBackupFile.createNewFile();
FileOutputStream backupStream = new FileOutputStream(newBackupFile);
//transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = dataBaseFile.read(buffer)) > 0) {
backupStream.write(buffer, 0, length);
}
//Close the streams
backupStream.flush();
backupStream.close();
dataBaseFile.close();
MediaScannerConnection.scanFile(this, new String[]{newBackupFile.getAbsolutePath()}, null, null);

Create text file to write/add of a couple of images name

I tried to get a script to create a text file that could write/add the images name, but the function
FileID = CreateFileForWriting(filename) does not work, it shows that was used by other process
I did not get this, is this function not right format or something is wrong, thx
Number Totaln
totaln=countdocumentwindowsoftype(5)
String filename, text
Number fileID
if (!SaveasDialog( "save text file as",getapplicationdirectory(2,0) + "Imagename.txt", filename))exit(0)
fileID = CreateFileForWriting(filename)
number i
for(i = 0; i <totaln; i++)
{
image imgSRC
imgSRC := GetFrontImage()
string imgname=getname(imgSRC)
WriteFile(fileID,"imgname")
Result("imgname")
}
Your code is nearly fine, but if you use the low-level API for file I/O you need to ensure that you close files you've opened or created.
Your script doesn't. Therefore, it runs fine exactly 1 time but will fail on re-run (when the file is still considered open.)
To fix it, you need to have closefile(fileID) at the end.
( BTW, if you script exits or throws after opening a file but before closing it, you have the same problem. )
However, I would strongly recommend not using the low-level API but the file streaming object instead. It also provides an automated file-closing mechanism so that you don't run into this issue.
Doing what you do in your script would be written as:
void writeCurrentImageNamesToText()
{
number nDoc = CountImageDocuments()
string filename
if (!SaveasDialog( "save text file as",getapplicationdirectory(2,0) + "Imagename.txt", filename)) return
number fileID = CreateFileForWriting(filename)
object fStream = NewStreamFromFileReference(fileID,1) // 1 for auto-close file when out of scope
for( number i = 0; i <nDoc; i++ ){
string name = GetImageDocument(i).ImageDocumentGetName()
fStream.StreamWriteAsText( 0, name + "\n" ) // 0 = use system encoding for text
}
}
writeCurrentImageNamesToText()

Any Efficient way to parse large text files and store parsing information?

My purpose is to parse text files and store information in respective tables.
I have to parse around 100 folders having more that 8000 files and whole size approximately 20GB.
When I tried to store whole file contents in a string, memory out exception was thrown.
That is
using (StreamReader objStream = new StreamReader(filename))
{
string fileDetails = objStream.ReadToEnd();
}
Hence I tried one logic like
using (StreamReader objStream = new StreamReader(filename))
{
// Getting total number of lines in a file
int fileLineCount = File.ReadLines(filename).Count();
if (fileLineCount < 90000)
{
fileDetails = objStream.ReadToEnd();
fileDetails = fileDetails.Replace(Environment.NewLine, "\n");
string[] fileInfo = fileDetails.ToString().Split('\n');
//call respective method for parsing and insertion
}
else
{
while ((firstLine = objStream.ReadLine()) != null)
{
lineCount++;
fileDetails = (fileDetails != string.Empty) ? string.Concat(fileDetails, "\n", firstLine)
: string.Concat(firstLine);
if (lineCount == 90000)
{
fileDetails = fileDetails.Replace(Environment.NewLine, "\n");
string[] fileInfo = fileDetails.ToString().Split('\n');
lineCount = 0;
//call respective method for parsing and insertion
}
}
//when content is 90057, to parse 57
if (lineCount < 90000 )
{
string[] fileInfo = fileDetails.ToString().Split('\n');
lineCount = 0;
//call respective method for parsing and insertion
}
}
}
Here 90,000 is the bulk size which is safe to process without giving out of memory exception for my case.
Still the process is taking more than 2 days for completion. I observed this is because of reading line by line.
Is there any better approach to handle this ?
Thanks in Advance :)
You can use a profiler to detect what sucks your performance. In this case it's obvious: disk access and string concatenation.
Do not read a file more than once. Let's take a look at your code. First of all, the line int fileLineCount = File.ReadLines(filename).Count(); means you read the whole file and discard what you've read. That's bad. Throw away your if (fileLineCount < 90000) and keep only else.
It almost doesn't matter if you read line-by-line in consecutive order or the whole file because reading is buffered in any case.
Avoid string concatenation, especially for long strings.
fileDetails = fileDetails.Replace(Environment.NewLine, "\n");
string[] fileInfo = fileDetails.ToString().Split('\n');
It's really bad. You read the file line-by-line, why do you do this replacement/split? File.ReadLines() gives you a collection of all lines. Just pass it to your parsing routine.
If you'll do this properly I expect significant speedup. It can be optimized further by reading files in a separate thread while processing them in the main. But this is another story.

JavaMail and non-ASCII character in filenames

I can send attachments that have non-ascii filenames in JavaMail but I am not able to download them. I am getting java.io.FileNotFoundException specifically for those attachments whose file names contain non-ascii characters.
FYI: I am using something like messageBodyPart.setFileName(MimeUtility.encodeText(filename[i])) to encode the text and MimeUtility.decodeText(bodyPart.getFileName()) to decode the non-ascii file names
Is there a workaround for this?
EDIT
#Bill, here is part of my code that reads attachments. I have also added the properties.setProperty("mail.mime.decodeparameters", "true") and properties.setProperty("mail.mime.decodefilename", "true") properties in my code.
if (message[a].getContent() instanceof MimeMultipart) {
Multipart multipart = (Multipart) message[a].getContent();
for (int i = 0; i < multipart.getCount(); i++) {
bodyPart = multipart.getBodyPart(i);
disposition = bodyPart.getDisposition();
if (disposition != null && (disposition.equals(BodyPart.ATTACHMENT) || (disposition.equals(BodyPart.INLINE)))) {
DataHandler handler = bodyPart.getDataHandler();
String path = bodyPart.getFileName();
String[] str = path.split("/");
String fileName = str[str.length - 1];
String filePath = ReadConfigPropertiesFile.getPropertyValue("server.buildpath");
System.out.println(fileName);
File tempDir = new File(filePath + user);
if (!tempDir.exists()) {
tempDir.mkdir();
}
File saveFile = new File(tempDir + "/" + fileName);
int count = 0;
while (saveFile.exists()) {
count++;
saveFile = new File(tempDir + "/" + count + "_" + fileName);
}
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(saveFile));
byte[] buff = new byte[2048];
InputStream is = bodyPart.getInputStream();
int ret = 0;
while ((ret = is.read(buff)) > 0) {
bos.write(buff, 0, ret);
}
bos.close();
is.close();
//System.out.println(bodyPart.getContentType());
}else {
//display body (message) of the attachment;
//System.out.println(bodyPart.getContent().toString());
}
}
}
The above code raises the FileNotFoundException exception at BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(saveFile)) line and this is getting raised for the attachments whose file names are non-ascii characters (something like ሰላም.pdf). Every thing else works fine.
This answer taken from comment of #semytech (OP). It was hard to find it there, so I will add it as answer for more visibility. It helped me with hebrew filenames.
MimeBodyPart attachment = new MimeBodyPart();
attachment.setFileName(MimeUtility.encodeText(filename, "UTF-8", null));
You should never need to do the encoding or decoding yourself.
There are two sets of properties you can set to tell JavaMail to do the encoding/decoding for you:
mail.mime.encodefilename/mail.mime.decodefilename
mail.mime.encodeparameters/mail.mime.decodeparameters
See the javadocs for the javax.mail.internet package for details.
The first set uses a non-standard encoding technique, similar to what you're doing yourself. This works fine with some older mailers that use this technique.
The second set uses a MIME standard encoding technique. This version works with most modern mailers.
None of this explains why you're getting FileNotFoundException, but then you didn't provide enough detail to know what you're doing when you get the exception.

Database problem: how to diagnose and fix the problem?

I created an application which stores values into the database and retrieves the stored data. While running an application in run mode everything seems to work fine (the values are stored and retrieved successfully) but when I run in the debug mode the process throws IllegalStateException and so far haven't found a cause.
The method which retrieves an object Recording is the following:
public Recording getRecording(String filename) {
Recording recording = null;
String where = RECORDING_FILENAME + "='" + filename + "'";
Log.v(TAG, "retrieving recording: filename = " + filename);
try {
cursor = db.query(DATABASE_TABLE_RECORDINGS, new String[]{RECORDING_FILENAME, RECORDING_TITLE, RECORDING_TAGS, RECORDING_PRIVACY_LEVEL, RECORDING_LOCATION, RECORDING_GEO_TAGS, RECORDING_GEO_TAGGING_ENABLED, RECORDING_TIME_SECONDS, RECORDING_SELECTED_COMMUNITY}, where, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
//String filename = c.getString(0);
String title = cursor.getString(1);
String tags = cursor.getString(2);
int privacyLevel = cursor.getInt(3);
String location = cursor.getString(4);
String geoTags = cursor.getString(5);
int iGeoTaggingEnabled = cursor.getInt(6);
String recordingTime = cursor.getString(7);
String communityID = cursor.getString(8);
cursor.close();
recording = new Recording(filename, title, tags, privacyLevel, location, geoTags, iGeoTaggingEnabled, recordingTime, communityID);
}
}
catch (SQLException e) {
String msg = e.getMessage();
Log.w(TAG, msg);
recording = null;
}
return recording;
}
and it is called from another class (Settings):
private Recording getRecording(String filename) {
dbAdapter = dbAdapter.open();
Recording recording = dbAdapter.getRecording(filename);
dbAdapter.close();
return recording;
}
While running through the code above everything works fine but then I notice an exception in another thread:
alt text http://img509.imageshack.us/img509/862/illegalstateexception.jpg
and don't know neither what is the possible cause of this exception nor how to debug the code from that thread to diagnose the cause.
I would be very thankful if anyone knew what is the possible issue here.
Thank you!
Looks like that cursor.close() is inside an "if" - that's when SQLiteCursor.finalize() will throw an IllegalStateException (I googled for it). You migh be getting an empty recordset, for instance, if some other process/thread didn't have the time to commit.
Close it always, even if it's result set is empty.
I'd also advice you to access fields by names, not indices, for future compatibility. And do both close()s in finally{} blocks.

Resources