Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Read file and change delimiter 2

Status
Not open for further replies.

campbellc

IS-IT--Management
Jul 3, 2007
26
0
0
US
I have an FTP Perl program that reads a records in a file to determine who to FTP the data file to. The problem is that not all the files are formatted the same. In one file the record can be terminated with CR/LF. So when you look at it in Notepad you have one records per line. I also could get a file that terminates the records with a tilda "~" so the data just wraps around when looking at it in Notepad. In the later case I set $/ = "~";

In my read I'm looking for a specific value. If I don't find that value I assume the $/ is set to the wrong delimiter. Is there a way to change the $/ and re-read the file from the top? Any way to set multiple delimiters?
 
I finally got it to work and it works great. I do have a couple of questions. The variables defined by the "Readonly" did not seem to work. Specifically those defined for the database connection.

Code:
# Constants
use Readonly;
Readonly my $DIR_NAME => 'c:/EDI/outbound/ftp';
Readonly my $DB_HOST => "VIT32";
Readonly my $DB_NAME => "EDIDB";
Readonly my $DB_USER => "reports";
Readonly my $DB_PASS => "reports";

# Set Parameters
our $errlog = @ARGV ? $ARGV[0] : 'C:/outmsg.txt';

# Connect to Database
our $dbh = DBI->connect(q/dbi:ODBC:DRIVER={SQL Server};Server=VIT32;attr=database=EDIDB/, $DB_USER, $DB_PASS, {
    PrintError => 0,
    RaiseError => 1
    }) or die $DBI::errstr;

Once I hard coded the information (see above) it worked. Also the only way I could get the connection string to work was by using the "q/". I tried different ways to quote the string...but nothing seemed to work. But what really has me confused is the Readonly. Any thoughts??
 
You might not have Readonly installed. Or it might not be the latest version. That was the one coding convention that I was actually somewhat reluctant to implement in your script, namely because I'm new to it. I've for the longest time used "use constant", but recently been converted to the more convenient Readonly since it allows easy interpolation.

If you're having trouble with it, I say remove it entirely and simply declare those variable with "our" to indicate their constant and global status.

Also, there is no reason why you should have to use q// as your string operator in the DBI->connect parameter. I suspect that this was just an XY solution to the root problem with Readonly. I suggest that you return it to interpolated variables without the use of Readonly.

- Miller
 
Miller -
A million thanks. The script is working great and I've been able to use it with very little modifications. I was able to resolve the problem with the ReadOnly and it is working.
I do have a questions about the email subject line as I'm not able to get a more meaningfull message to display. All that displays now is technical information that the user is not going to understand. Reading several books on the "shift" function...it is my understanding that the first indexed value of the @_ array is deleted with the remaining values shifted one to the left.

So...in the following example
Code:
or die "Cannot connect to database: $DBI::errstr\n";
The english like statement would be deleted and replaced with the technical DBI error. I've tried using $_[0] and removing the shift command. How do I get a more english like statement to apprear in the subject of the email?

Thanks...
Chris
 
How do I get a more english like statement to apprear in the subject of the email?

Unless you are able and willing to write those statemets yourself based on the current value of $subject, there is no way that I know of to do what you want. The error messages are what they are, they are sometimes cryptic and generally technical.

You could replace $subject with a generic value: "an error has occured" which is not very useful.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
As Kevin says, if you want more, you're going to have to program it.

I would like to point out that there are two bugs that the script is currently not taking into account.

Question 1) When a file fails and is moved to "send_failedBLAH", what keeps it from being reparsed the next time the script is run? I would suggest that you include a next statement at the beginning of the FILE loop.

Code:
[maroon]FILE[/maroon][maroon]:[/maroon]
[olive][b]foreach[/b][/olive] [url=http://perldoc.perl.org/functions/my.html][black][b]my[/b][/black][/url] [blue]$file[/blue] [red]([/red][blue]@files[/blue][red])[/red] [red]{[/red]
	[olive][b]next[/b][/olive] [olive][b]if[/b][/olive] [red]/[/red][purple]^send_failed_[/purple][red]/[/red][red];[/red] [gray][i]# Skip previously failed files[/i][/gray]

Question 2) What keeps a string of failing files from overwriting each other when moved to send_failed_*?

Answer 1) Well, they are currently created using %d%H%M%S, so as long as none of them are created on the same second, they we should be fine. Note that in the very beginning of the FILE loop you rest for 1 second. Don't know why this is done, but this takes care of the 1 second differential (maybe). However, since this solution is obscure and not 100% garanteed, another solution should be proposed.

Question 2b) What about when the next month occurs?

Answer 2b) Yes, that could lead to more obvious (although statistically rare) overlaps. To avoid even this small possibility, lets go ahead and add some unique file protection.
Code:
		[url=http://perldoc.perl.org/functions/print.html][black][b]print[/b][/black][/url] [red]"[/red][purple]File '[blue]$file[/blue]' failed: Going to move[purple][b]\n[/b][/purple][/purple][red]"[/red][red];[/red]
		[url=http://perldoc.perl.org/functions/my.html][black][b]my[/b][/black][/url] [blue]$oldfile[/blue] = [red]"[/red][purple][blue]$DIR_NAME[/blue]/[blue]$file[/blue][/purple][red]"[/red][red];[/red]
		[black][b]my[/b][/black] [blue]$newfile[/blue] = [red]"[/red][purple][blue]$DIR_NAME[/blue]/send_failed_[/purple][red]"[/red].[maroon]strftime[/maroon][red]([/red][red]"[/red][purple]%d%H%M%S[/purple][red]"[/red], [url=http://perldoc.perl.org/functions/localtime.html][black][b]localtime[/b][/black][/url][red])[/red][red];[/red]
		
		[gray][i]# Ensure unique destination.[/i][/gray]
		[black][b]my[/b][/black] [red]([/red][blue]$basename[/blue], [blue]$cntr[/blue], [blue]$fh[/blue][red])[/red] = [red]([/red][blue]$newfile[/blue], [fuchsia]1[/fuchsia][red])[/red][red];[/red]
		[olive][b]until[/b][/olive] [red]([/red][blue]$fh[/blue] = IO::File->[maroon]new[/maroon][red]([/red][blue]$newfile[/blue], O_RDWR|O_CREAT|O_EXCL[red])[/red][red])[/red] [red]{[/red]
			[blue]$newfile[/blue] = [blue]$base[/blue] . [red]'[/red][purple]_[/purple][red]'[/red] . [blue]$cntr[/blue]++[red];[/red]
		[red]}[/red]
		
		[maroon]move[/maroon][red]([/red][blue]$oldfile[/blue], [blue]$fh[/blue][red])[/red] or [url=http://perldoc.perl.org/functions/warn.html][black][b]warn[/b][/black][/url] [red]"[/red][purple]Can't move: [blue]$![/blue][/purple][red]"[/red][red];[/red]

- Miller
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top