Automate the download of a list of URLs/links

I just wanted to automate the process of downloading a list of URLs/links. I thought about asking a question at SuperUser. So I did that and got a few answers. One of those answers pointed to the piece of software that does exactly what I wanted. The software is a Firefox add-on that I had used a long time ago but couldn’t think about it for this task. Its name is DownThemAll!. Yes with an exclamation mark at the end. I think this has to do with a relief felling you feel when you’re using it.

In this post I’ll walk you through the steps necessary to get your downloads going in a really fast way (fasten your seat belt). No more downloading and saving file by file. Phew!

I’m going to use the same list of URLs I posted on my question at SuperUser.

Suppose you have a list of URLs as this one:

http://creamteam.tv/wp-content/uploads/2010/06/10-Chinatown.mp3
http://mp3muffin.com/train/burbs.mp3
http://www.knoxroad.com/wp-content/music/May/01%20World%20Sick.mp3
http://indierockcafe.com/mp3s/2010/may/5-18/bandofhorses_factory1.mp3
http://www.strangefamousrecords.com/sfr-audio/_common/sagefrancis_slowman.mp3
http://dangerbirdrecords.com/public/theoneamradio/crediblethreats.mp3
http://www.beggarsgroupusa.com/mp3/HolyFuck_LatinAmerica.mp3
http://dl.dropbox.com/u/4746099/05%20Choices%201.mp3
http://subpop-public.s3.amazonaws.com/assets/audio/6801.mp3
http://gvsbchris.com/01%20Sleep%20Paralysist.mp3
http://bantermm.com/tracks/Annuals-Loxtep.mp3
http://downloads.pitchforkmedia.com/The%20National%20-%20Bloodbuzz%20Ohio.mp3
http://stereogum.com/mp3/the%20morning%20benders%20-%20Excuses.mp3

Save this list in a text file [ .txt ] extension and name it MP3s.txt.

Now let’s get DownThemAll! and do the real thing…

1 - Install DownThemAll! add-on for Firefox. After installing restart Firefox.

2 - Go to Firefox menu and select Tools - DownThemAll! Tools - Manager... Right-click inside DownThemAll! screen.

3 - Select context menu Misc - Import from file.

4 - On Import downloads dialog window make sure you select Text Files in the dropdown list.

5 - Point to the text file MP3s.txt that contains the URLs. Click Open button.

6 - On Make your selection dialog window, DownThemAll! will load each link it finds in the text file allowing you to select which ones you want to download and the folder where you want the files to be saved as well.

7 - Make your selections, click Start button.

Here's a screenshot of it just doing the "Downloading" part:

DownThemAll! downloading the list of URLs from my question at SuperUser
Figure 1 - DownThemAll! downloading the list of URLs from my question at SuperUser

Oh… and this is the feature request on DownThemAll! trac opened 3 years ago.

Nice to see this implemented and working so well.

Congrats to DownThemAll! developers and users. Fantastic add-on.

StackOverflow: best place to share/learn programming

I’ve been spending some time of my days helping others at StackOverflow. StackOverflow (SO) is the best place to ask questions related to software programming. There you can be sure that someone somewhere will help you to find an answer to your question.

Note: I just got out of my job at Chemtech. Now I have more time to focus in other things and to think a little bit more about what I want to do next.

As a consequence I decided that I’ll try to give back and share a portion of the knowledge I acquired in these 7 years of programming experience. By means of helping others at StackOverflow I just improve what I think I already know. This is a bit controversial you may say, but I don’t think so. I’m constantly learning/unlearning and discovering new things at SO. I keep trying to sharpen my programming skills. This just happens somewhat in a recursive way. One finding leads to other that then brings you back to the main topic that then expands and so forth.

Give, and it will be given to you. Good measure, pressed down, shaken together, running over, will be put into your lap. For with the measure you use it will be measured back to you.
Luke 6:38

I’m kind of a generalist (I’m after the generalist badge), that is, I don’t tie myself to any technology. I’ll try to use the one that fits better in a given task/job be it close-source or open-source. If a technology allows me to get the thing done that’s the one I’ll choose. This is reflected in the variety of tags at my StackOverflow profile:


Of course there are well established technologies that are easier to work with as is the case of C# programming language, ASP.NET, Java, etc. Again this can be seen both on my tags and in the quantity of questions tagged with such technologies. Being easier to work with means having a greater user base throughout the world and this is reflected at StackOverflow tags as well.

The title of this post is what motivated me to write and I hope will motivate others too so that they give back a portion of what they know.

The point is this: whoever sows sparingly will also reap sparingly, and whoever sows bountifully will also reap bountifully. Each one must give as he has decided in his heart, not reluctantly or under compulsion, for God loves a cheerful giver. And God is able to make all grace abound to you, so that having all sufficiency in all things at all times, you may abound in every good work.
2 Corinthians 9:6-8

I then invite you: if you’d like to get free answers to your coding questions or if you want to write better code or if you want to start at SO and be happy or whatever related to coding problems, I suggest you to read the FAQ and create an account at SO.

You see, we should help each other. There are times that we get stuck at some coding problems for hours and we don’t know what to do to get over them. With millions of programming peers having the most varied backgrounds willing to help and sharing what they know is what makes a developer’s life valuable and exciting. At StackOverflow you find what summarizes this last phrase. In just a minute you can get an answer that’ll allow you to continue your work. If you compare minutes to hours it’s clear why StackOverflow is so fantastic.

The sum of our good programming efforts builds a better software product. LOL <(^^,)> 
By Leniel Macaferi

As of the time of this writing, for stats purposes, I have 4257 reputation,18 badges, 2 questions asked and 288 questions answered at SO. A pretty good amount of answers as a start for someone who’s also after the fanatic badge. I can assure you I’m more than half way there already. Badges are not the point of this post but they make the whole thing a little bit more motivating. Badges at SO are recognitions that come with time just as in real life. The more you share the more recognition you earn.

I take my hat off to the people that started such great site. I hope that it grows even more in the years to come with more and more users trying to learn this admirable profession of software developer that in my humble opinion is the best one. I’m biased towards it after all.

At SO we just happen to have pretty good discussions about anything related to programming including What’s your favorite “programmer” cartoon? and Is a master’s degree overkill? ranging to the more diverse topics. In one of those really interesting discussions I found this brilliant saying that I think holds true in this world:

When you finish your bachelor's, you think you know everything; When you finish your master's, you realize you know nothing; When you finish your doctorate, you realize nobody knows anything, including whether or not you needed to finish a doctorate to realize that.
By Unknown

Although I haven’t taken a master’s or doctorate course yet I can write about the bachelor’s part. When I finished the bachelor’s I already knew that I didn’t know nothing. I think that when I finish the master’s I’ll realize nobody knows anything. One less step to realize that. What will happen then if I take a doctorate course? Simply put: (no one knows nothing ) ^ Googol I think. :)

Final Note: I also put in practice this same share and learn principle at ProZ.com.

Further references
I suggest you check these two posts by Jon Skeet:

Writing the perfect question
Answering technical questions helpfully

Manipulating Properties and Methods with Reflection

Today I’m going to write about a simple yet powerful way to manipulate properties and methods of a given type. We’ll set values to properties and invoke methods through the use of reflection.

Maybe you haven’t had the chance to use reflection or maybe you even don’t know what is reflection.

Reflection is one of the most powerful features a programming language has as is the case of C# programming language that I’ll be using in this post.

In just one phrase extracted from Wikipedia we can define what is reflection:

Reflection is the process by which a computer program can observe and modify its own structure and behavior. The programming paradigm driven by reflection is called reflective programming.

Our objective is to manipulate the property value and methods of a type by means of reflection, that is, we’ll have access to these properties and methods by looking at the type’s metadata.

Let’s exemplify with a specific case that I came into while I was working on my first project at Chemtech: we had our ASP.NET solution divided into specific projects in what we call the MVP pattern. I suggest that you to read the post Model View Presenter pattern with Castle in ASP.NET to get a grasp of it.

In a given task I had 15 static textboxes inside an .aspx page (View) and I needed to set their values inside the Presenter. What is the best way to do it? Should you hardcode each and every textbox setting their values? It’s not an elegant solution. So how to get over it? Using reflection to get the type’s metadata. Let’s see how it is easy.

Let’s get to the code:

private void BindProperty(string viewPropertyName, object propertyValue)
{
    // Getting the property I want to use.
    PropertyInfo propertyInfo = typeof(IMyView).GetProperty(viewPropertyName);

    // Verifying if the property was acquired with success.
    if (propertyInfo != null && propertyInfo.CanWrite)
    {
        // Set the property value.
        propertyInfo.SetValue(view, propertyValue, null);
    }
}

Reflection allows us to make a generic piece of code, that is, with only one method we can set the value of all the textboxes.

The above method receives the property name as a parameter and we also pass to the method the value we want to assign to the property.

This same approach can be used with methods. Let’s see an example:

private void BindMethod(string viewMethodName, object[] methodParameters)
{
    // Getting the method I want to use.
    MethodInfo methodInfo = typeof(IMyView).GetMethod(viewMethodName);

    if (methodInfo !=null)
    {
// Call/Invoke the method with the desired parameters. methodInfo.Invoke(view, methodParameters); } }

Again we have a generic piece of code that can be used to call whatever method we want passing whatever parameters we want.

To use PropertyInfo and MethodInfo we declare the namespace System.Reflection.

We could make these methods even more generic by passing the view object (type) we want as a parameter. Bellow I show a class named ReflectionUtil with such modifications:

/// <summary>
/// Utility class for Reflection operations.
/// </summary>
public class ReflectionUtil
{
    /// <summary>
    /// Sets a value to a property through the use of Reflection.
    /// </summary>
    /// <param name="obj">Object that owns the property</param>
    /// <param name="propertyName">Property name</param>
    /// <param name="propertyValue">Value to be set</param>
    public static void BindProperty(object obj, string propertyName, object propertyValue)
    {
        // Getting the property I want to use.
        PropertyInfo propertyInfo = obj.GetType().GetProperty(propertyName);

        // Verifying if the property was acquired with success.
        if (propertyInfo != null && propertyInfo.CanWrite)
        {
            // Set the property value.
            propertyInfo.SetValue(obj, propertyValue, null);
        }
    }

    /// <summary>
    /// Calls a method through the use of Reflection.
    /// </summary>
    /// <param name="obj">Object that owns the method</param>
    /// <param name="methodName">Method name</param>
    /// <param name="methodParameters">Method parameters</param>
    public static void BindMethod(object obj, string methodName, object[] methodParameters)
    {
        // Getting the method I want to use.
        MethodInfo methodInfo = obj.GetType().GetMethod(methodName);

        if (methodInfo != null)
        {
// Call/Invoke the method with the desired parameters. methodInfo.Invoke(obj, methodParameters); } } }

OK. Now that we have the methods defined, let’s use them.

I’ll use the application I’ve shown in Model View Presenter pattern with Castle in ASP.NET as the base for this post.

IMyView interface declares the following members:

public interface IMyView : IBaseView
{
    event EventHandler FirstLoading;

    void MyMethod();

    string TextBox1Text { set; }
    string TextBox2Text { set; }
    string TextBox3Text { set; }
    string TextBox4Text { set; }
    string TextBox5Text { set; }
    string TextBox6Text { set; }
    string TextBox7Text { set; }
    string TextBox8Text { set; }
    string TextBox9Text { set; }
    string TextBox10Text { set; }

    void FillGridView1(List<object> values);
    void FillGridView2(List<object> values);
}

MyView implements what’s in IMyView interface:

public partial class MyView : Page, IMyView
{
    private MyPresenter presenter;

    .
.
.
#region Implementation of IMyView public event EventHandler FirstLoading; public void MyMethod() { Response.Write("Reflection power"); } #region TextBoxes public string TextBox1Text { set { TextBox1.Text = value; } } public string TextBox2Text { set { TextBox2.Text = value; } }

.
.
. #endregion #region Methods public void FillGridView1(List<object> values) { GridView1.DataSource = values; GridView1.DataBind(); } public void FillGridView2(List<object> values) { GridView2.DataSource = values; GridView2.DataBind(); } #endregion #endregion }

Inside the Presenter MyPresenter I implement the logic with the following:

/// <summary>
/// Specific FirstLoading implemented by each inheritor
/// </summary>
protected override void FirstLoading()
{
    view.MyMethod();

    // Useful technique to avoid calling 10 lines of code.
    for (int i = 1; i <= 10; i++)
    {
        ReflectionUtil.BindProperty(view, string.Format("TextBox{0}Text", i), (i * i).ToString());
    }

    // Useful technique to avoid writing methods almost identical just to change a method call.
    for (int i = 1; i <= 2; i++)
    {
        // Do some common logic here...

        // Call a specific method with Reflection.
ReflectionUtil.BindMethod(view, string.Format("FillGridView{0}", i), new object[] { new List<object> { i * 2, i * 3, i * 4, i * 5 } }); // Do some common logic here... } }

When we run the web app, we get the following result:

Reflection result

I covered just a simple use case of reflection in this post but it’s useful in our day to day job.

The technique implemented in this post allows us to write clean and generic code. I have already used it in another project which allowed me to write as few lines of code as possible. Let’s say it decreased from 250 sloc to 25 sloc. A reduction of 10 times sloc.

Last note
I read the article Survival of the Fittest: Natural Selection with Windows Forms on MSDN Magazine when I was on the 9th period of the Computer Engineering course studying Artificial Intelligence. From this moment on I started to visualize the importance of reflection and how powerful it is. The referenced article discusses about Genetic Algorithms and the author’s sample code makes extensive use of reflection. Great read if you’re interested enough! Oh, I even translated this article to Portuguese at that time. I want to put it online so that others can benefit from it. :o)

Visual Studio 2010 C# ASP.NET Web Application
You can get the Microsoft Visual Studio Project at:

http://sites.google.com/site/leniel/blog/ReflectionWebApp.zip

To try out the code you can use the free Microsoft Visual Web Developer 2010 Express Edition that you can get at: http://www.microsoft.com/express/Web/

Mp3tag to batch process/edit MP3 tags

It’s always good to keep things organized even more when it comes to MP3 files. If you use to listen to MP3 music you know what I’m talking about.

I keep a timeline of music I listen to at Last.fm. Last.fm tries to help us correcting wrong MP3 tags, but corrections are only visible online and they don’t change MP3 metadata, that is, you still have wrongly tagged MP3 residing in your music library.

To overcome such situation I started looking for a piece of software that could resolve this misinformation. I got to know a free yet powerful small application called Mp3tag that allows the execution of various commands against MP3 metadata.

Excerpting from the official site:

Mp3tag is a powerful and yet easy-to-use tool to edit metadata of common audio formats where it supports ID3v1, ID3v2.3, ID3v2.4, iTunes MP4, WMA, Vorbis Comments and APE Tags.

It can rename files based on the tag information, replace characters or words in tags and filenames, import/export tag information, create playlists and more.

Mp3tag supports online database lookups from, e.g., Amazon, discogs, or freedb, allowing you to automatically gather proper tags and cover art for your music library.

One of the best features of Mp3tag is the Actions menu button that let’s you replace text within any MP3 tag field using simple find and replace or more advanced regular expressions. The following figure shows the options available:

Figure 1 – Options available through the Actions menu button
Figure 1 – Options available through the Actions menu button

I’ll briefly show how to edit the Title of some files all at once - what is known as batch processing.

I’ll remove with only one command (action) the text “ - TO BE REMOVED” that is part of the Title tag of 10 MP3 files:

Figure 2 – Mp3tag listing 10 MP3 files before the batch processing
Figure 2 – Mp3tag listing 10 MP3 files before the batch processing

Click on the Action menu button (mouse pointer is over it in the following picture) and select the action type as Replace and click OK:

Figure 3 – Mp3tag action type selection
Figure 3 – Mp3tag action type selection

Now select the MP3 tag field you’d like to change. In this case I’m going to modify the content of the Title tag field. Enter the text “ - TO BE REMOVED” inside the Original field. As I want to remove the text I’ll let the Replace with field blank/empty.

Figure 4 – Mp3tag Replace action window
Figure 4 – Mp3tag Replace action window

Click OK and voila:

Figure 5 – Mp3tag listing 10 MP3 files after the batch processing
Figure 5 – Mp3tag listing 10 MP3 files after the batch processing

Now you know where to look for a versatile MP3 tag editor. It comes to the rescue allowing you to avoid spending your time editing MP3 by MP3. You can do lots of things related to MP3 metadata. You can batch process all your MP3 with only one action easy as pie.

It would be good if popular media players as Windows Media Player, iTunes, etc could let us do things like this simple task I demonstrated in this post. Maybe someday they will. I hope.

References
Mp3tag online Help
Mp3tag group at Last.fm
Mp3tag at Twitter

Oracle NLS_LANG for language/territory/character set

Recently I had an Oracle problem at work.
I kept postponing to look with care at this problem till today.

Problem
All accented characters as à, á, é, í, ó, ú, â, ê, î, ô, û, ã, õ, etc and other ones as ç (cedilla), º, ª (ordinal indicators), were being replaced by erroneous characters as this example in the header of a stored procedure:

=================================================================
-- Revis¿o : 'N¡ã 0
-- Descri¿¿o: // description here
-- Data   : 03/29/2010
-- Autor  : CHEMTECH
=================================================================

This problem gets worse if you have something as

SELECT CONTRACT.NUM_CONTRACT,
           'N¡ã' || TO_CHAR(CONTRACT.NUM_CONTRACT) || ' - ' ||

The result of the above SQL query is used in the UI, that is, the user will see the wrong characters ¡ã instead of º. If you commit this thing in the repository you mess everything up. You see what I mean…

Questioning
At first I thought the problem was the database encoding settings.

I and only I was getting crazy characters. My development group has more 3 people and no one was having this problem. This clearly should be a UI configuration, that is, how the data is shown on my machine.

A little bit of research on the net took me to Oracle’s NLS_LANG FAQ.

This is what NLS_LANG stands for/does:

A locale is a set of information addressing linguistic and cultural requirements that corresponds to a given language and country. Traditionally, the data associated with a locale provides support for formatting and parsing of dates, times, numbers, and currencies, etc. Providing current and correct locale data has historically been the responsibility of each platform owner or vendor, leading to inconsistencies and errors in locale data.

Setting the NLS_LANG environment parameter is the simplest way to specify locale behavior for Oracle software. It sets the language and territory used by the client application and the database server. It also indicates the client's character set, which corresponds to the character set for data to be entered or displayed by a client program.

I started reading the FAQ (top bottom approach) and tried the following query:

SELECT * FROM NLS_SESSION_PARAMETERS;

which gave me this result:

NLS_SESSION_PARAMETERS on my development machine
Figure 1 - NLS_SESSION_PARAMETERS on my development machine

As you see NLS_LANGUAGE and NLS_TERRITORY are set to AMERICAN and AMERICA respectively on my machine.

I asked Thiago Arakaki a coworker of mine to execute the same SQL query on his dev box. To my surprise and delight this was the screen he got:

NLS_SESSION_PARAMETERS on Thiago's development machine
Figure 2 - NLS_SESSION_PARAMETERS on Thiago Arakaki’s development machine 

As you see NLS_LANGUAGE and NLS_TERRITORY are set to BRAZILIAN PORTUGUESE and BRAZIL respectively on his machine.

This clearly pointed what could be the cause of the problem I was having.

I couldn’t understand why my machine had a different NLS_LANGUAGE and NLS_TERRITORY.

I read the FAQ a little bit more and got to this part Where to set the NLS_LANG in Windows.

I checked Windows registry to make sure the NLS_LANG subkey was set correctly on Oracle home. I got this:

NLS_LANG subkey on Windows RegistryFigure 3 - NLS_LANG subkey on Windows Registry

For my surprise it was correct. Look at NLS_LANG. It has BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252 just like Thiago Arakaki’s dev box.

So why do I still was getting wrong characters inside Allround Automations PL/SQL Developer when working on the same database that Thiago also uses? Aha, that’s the question this post tries to clarify if you come to get in this same situation.

Reading the FAQ a little bit more… :o) I saw that you could also set NLS_LANG as a System or User Environment Variable, in System properties. So I went there to check if I already had such a thingy set on my machine. Again for my surprise this thingy was there. I don’t remember if/when I created this variable.

The only thing I thought at the moment was the interference that some previous installations of Oracle could’ve caused on my machine. Today I’m using Oracle express but in the past I installed the full Oracle server. I can’t state for sure what created the NLS_LANG var on my Windows System variables.

The screen I got was something like this:

 NLS_LANG variable on Windows System variables
Figure 4 - NLS_LANG variable on Windows System variables

I had AMERICAN set for the NLS_LANG variable.

Solution
I then changed the system variable NLS_LANG to BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252. Clicked OK. Closed PL/SQL. Opened PL/SQL and issued the SQL query described on the beginning of this post and could see that the NLS_LANGUAGE and NLS_TERRITORY rows had changed appropriately to BRAZILIAN PORTUGUESE and BRAZIL respectively. After that I started to get the right characters throughout the database.

Great! Problem solved.

Upload/Import Download/Export a File to/from Oracle DB

What motivated me to write this post is that this is a really interesting task.

The general idea one have about databases is that they only serve the purpose of storing plain values as numbers, dates and text. A database does not do just that but even more allowing you to store a whole file as an Excel spreadsheet or an MP3 file in a column you define in your table.

To illustrate that, let’s suppose you were assigned the task of saving a spreadsheet in the database. This spreadsheet contains valuable data (as taxes values for each federal state) that’ll be used throughout your application. A user will upload that spreadsheet to the database and when someone else want to see the content of that spreadsheet it’s just a matter of clicking a download button to get it back. Pretty simple, isn’t it?

To accomplish that I’ll use Oracle database, more specifically Oracle Database 10g Express Edition (free to use).

The SQL code I used to create the database objects is as follows:

----------------------------------------------------------
-- Export file for user ORACLETEST                      --
-- Created by Leniel Macaferi on 3/13/2010, 11:43:17 PM --
----------------------------------------------------------

-- Create database tablespace
create tablespace oracletest datafile 'C:\oracletest.dbf'
size                                  20M
autoextend on maxsize                 unlimited
extent management local uniform size  64K;

-- Create user and Grant permissions
create user oracletest identified by oracletest default tablespace oracletest;
grant connect, resource to oracletest;
grant create session to oracletest;
grant unlimited tablespace to oracletest;
grant dba to oracletest;

-- Create table
create table FILES
(
  ID          NUMBER not null,
  UPLOAD_DATE DATE not null,
  CONTENT     BLOB not null,
  TYPE        VARCHAR2(64) not null,
  NAME        VARCHAR2(128) not null,
LENGTH NUMBER not null
);
alter table oracletest.FILES
  add constraint ID primary key (ID);

-- Create sequence
create sequence oracletest.SEQ_FILES
minvalue 1
maxvalue 999999999999999999999999999
start with 1
increment by 1
nocache;
-- Create import/upload procedure
create or replace procedure sp_import_file(
upload_date
in varchar2, content files.content%type, type in varchar2, name in varchar2,
length in number, id
out number) is begin select seq_files.nextval into id from dual; insert into files (id, upload_date, content, type, name, length) values (id, to_date(upload_date, 'mm/dd/yyyy hh:mi:ss pm'), content, type, name,
length
); end sp_import_file;

I’ll use an ASP.NET MVC application to show the process of uploading/importing downloading/exporting a file to/from an Oracle database.

The app has a tab called Import/Export File. Clicking on this tab takes you to a View that contains a file upload control and two buttons. When the user clicks the Import button the file will be uploaded/imported/saved to/in the database. When the user clicks the Export button the last file saved in the database will be downloaded/exported to the user’s computer.

The following is a screenshot of the application:

Oracle Import Export File ASP.NET MVC Application
Figure 1 - ASP.NET MVC Application UI

The following is a screenshot of the Files table which already has some files:

Oracle Import Export Files Table
Figure 2 - Oracle Files Table

As you can see the thing that makes it possible to import a whole file to a table is the type of the column that’ll hold the file; in this case the type is BLOB.

In the lines that follow I’ll present the source code I used to implement this sample ASP.NET MVC application.

It’s always good to view the Solution Explorer inside Visual Studio so that I can highlight the files I have created:

Oracle Import Export File Visual Studio Solution Explorer Figure 3 - Solution Explorer in Visual Studio

This is the C# code used in the upload/import process (inside OracleFileModel.cs):

/// <summary>
/// Imports any file to an Oracle database table that has a column of type BLOB.
/// </summary>
/// <param name="uploadDate">Date of upload/importation</param>
/// <param name="fileName">File name</param>
/// <param name="filePath">File path on the server</param>
/// <param name="fileType">File type</param>
/// <param name="fileSize">File size in bytes</param> /// <returns>Id of Row just inserted</returns> public static int Import(string uploadDate, string fileName, string filePath, string fileType, int fileSize) { OracleConnection connection = GetOracleConnection(); connection.Open(); OracleTransaction transaction; transaction = connection.BeginTransaction(); OracleCommand cmd; cmd = connection.CreateCommand(); cmd.Transaction = transaction; // Creates a temporary blob object on the database. This object will store the file content. cmd.CommandText = "declare xx blob; begin dbms_lob.createtemporary(xx, false, 0); :tempblob := xx; end;"; cmd.Parameters.Add(new OracleParameter("tempblob", OracleType.Blob)).Direction = ParameterDirection.Output; cmd.ExecuteNonQuery(); // Getting the content of the file... byte[] buffer = GetFileContent(filePath); // Oracle object responsible for storing the File content. OracleLob tempLob; // Assigning tempLob the blob object created on the database. tempLob = (OracleLob)cmd.Parameters[0].Value; tempLob.BeginBatch(OracleLobOpenMode.ReadWrite); // Writing the file content to tempLob. tempLob.Write(buffer, 0, buffer.Length); tempLob.EndBatch(); cmd.Parameters.Clear(); // The name of the Procedure responsible for inserting the data in the table. cmd.CommandText = "SP_IMPORT_FILE"; cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(new OracleParameter("upload_date", OracleType.VarChar)).Value = uploadDate; cmd.Parameters.Add(new OracleParameter("content", OracleType.Blob)).Value = tempLob; cmd.Parameters.Add(new OracleParameter("type", OracleType.VarChar)).Value = fileType; cmd.Parameters.Add(new OracleParameter("name", OracleType.VarChar)).Value = fileName;
cmd.Parameters.Add(new OracleParameter("length", OracleType.Number)).Value = fileSize; cmd.Parameters.Add(new OracleParameter("id", OracleType.Number)).Direction = ParameterDirection.Output; try { cmd.ExecuteNonQuery(); } catch (Exception ex) { transaction.Rollback(); throw new Exception(ex.Message); } transaction.Commit(); connection.Close(); // Returning the Id of the row just inserted in table FILES. // This Id could be used to associate the file inserted with another table, for example, // if you had to parse the content of a spreadsheet and save each line in other table. return int.Parse(cmd.Parameters[4].Value.ToString()); }
This is the C# code used in the download/export process (inside OracleFileModel.cs)::
/// <summary>
/// Exports the last file imported to an Oracle database table that has a column of type BLOB.
/// </summary>
/// <returns>File</returns>
public static MyFileModel Export()
{
    MyFileModel file = new MyFileModel();

    OracleConnection connection = GetOracleConnection();
    connection.Open();

    OracleCommand cmd;
    cmd = connection.CreateCommand();

    // Gets the last File imported.
    cmd.CommandText = "select content, name, type from (select content, name, type from files f order by f.upload_date desc) where rownum = 1";

    byte[] fileContent;

    try
    {
        OracleDataReader reader = cmd.ExecuteReader();

        using (reader)
        {
            reader.Read();

            if (!reader.HasRows)
            {
                return file;
            }

            OracleLob blob = reader.GetOracleLob(0);
            OracleString fileName = reader.GetOracleString(1);
            OracleString fileType = reader.GetOracleString(2);

            fileContent = new byte[blob.Length];

            blob.Read(fileContent, 0, (int)blob.Length);

            file.Content = fileContent;
            file.Name = fileName.Value;
            file.Type = fileType.Value;
        }
    }
    catch (Exception ex)
    {
        throw new Exception(ex.Message);
    }

    connection.Close();

    return file;
}
/// <summary>
/// Gets an Oracle connection to the database.
/// </summary>
/// <returns>OracleConnection</returns>
private static OracleConnection GetOracleConnection()
{
    string user = ConfigurationManager.AppSettings["user"];
    string password = ConfigurationManager.AppSettings["password"];
    string dataSource = ConfigurationManager.AppSettings["dataSource"];

   return new OracleConnection("Data Source=" + dataSource + ";User Id=" + user + ";Password=" + password + ";");
}

/// <summary>
/// Get the content of the file in byte array buffer.
/// </summary>
/// <param name="path">File path on the server</param>
/// <returns>File content</returns>
private static byte[] GetFileContent(string path)
{
    Stream fs = File.OpenRead(path);
    
    byte[] buffer = new byte[fs.Length];

    int q = fs.Read(buffer, 0, Convert.ToInt32(fs.Length));

    fs.Close();

    return buffer;
}

This is the code implemented for the OracleFileController:

public class OracleFileController : Controller
{
    //
    // GET: /OracleFile/

    public ActionResult OracleFile(FormCollection formCollection)
    {
// Handles the button that posted to the server...
// OracleFile.aspx has 2 submit buttons.


if (formCollection["Import"] != null) { Import(); } else if (formCollection["Export"] != null) { return Export(); } return View(); } /// <summary> /// Imports a file from the user computer to the database. /// </summary> /// <returns></returns> private void Import() { foreach (string fileName in Request.Files) {
// Gets the file the user selected. HttpPostedFileBase file = Request.Files[fileName];
if (file.ContentLength > 0) {
// Getting the name of the folder in which the file will be saved on the server. string saveFolder = ConfigurationManager.AppSettings["saveFolder"];
                // Creating the path for the file on the server.

string filePath = Path.Combine(Request.ServerVariables["APPL_PHYSICAL_PATH"] + saveFolder, Path.GetFileName(file.FileName));
                // Saving a copy of the user's posted file on the server.
file.SaveAs(filePath);
                // Save the file in the database.
                // Although id isn't being used, this shows you how to get the id of the file just inserted in the database.
                int id = OracleFileModel.Import(DateTime.Now.ToString(), file.FileName, filePath, file.ContentType, file.ContentLength);
                // Deleting the file just imported so that the server disk does not get full.
                System.IO.File.Delete(filePath);

                TempData["message"] = "File imported with sucess.";
            }
        }
    }

    /// <summary>
    /// Exports a file from the database to the user's computer.
    /// </summary>
    /// <returns></returns>
    public ActionResult Export()
    {
        // Get the file from the database.
        MyFileModel file = OracleFileModel.Export();

        if (file.Content != null)
        {
            TempData["message"] = "File exported with success.";

            // Return the file to the user's computer.
            return File(file.Content, file.Type, file.Name);
        }
        else
        {
            TempData["message"] = "There's nothing to download.";

            return View("OracleFile");
        }
    }
}

This is a really big post full of code. I think the code has sufficient comments that should shed some light on how to accomplish the task.

Important note
All properties read in the form of ConfigurationManager.AppSettings["property"]; including the database name and password are stored in the Web.config file under the appSettings section.

<appSettings>
   <add key="user" value="oracletest"/>
   <add key="password" value="oracletest"/>
   <add key="dataSource" value="localhost"/>
   <add key="saveFolder" value="Files"/>
</appSettings>

Hope you make good use of it.

Visual Studio 2010 C# ASP.NET MVC Application
You can get the Microsoft Visual Studio Project at:

http://sites.google.com/site/leniel/blog/OracleImportExportFile.zip

To try out the code you can use the free Microsoft Visual Studio 2010 Professional Release Candidate (ISO file) that you can get at: http://www.microsoft.com/downloads/details.aspx?FamilyID=f9c0b89b-4964-4906-94c6-60ad8a429690&displaylang=en

Although I’ve used the 2010 version of Visual Studio I think the code presented in this post works just fine with previous versions of Visual Studio and ASP.NET MVC framework. You shouldn’t have problems while copying/pasting the code in previous versions. Maybe you’ll have to change DLL references or something like that.

Translation @ a click with Babylon

As a form of gratitude to Babylon I decided to write this post. A post is worth a thousand words almost literally in this case.

When it comes to computer translation, don’t think twice. Take a look at Babylon. Babylon is a Windows client application that resides in you taskbar. It offers translation from/to a varied set of language pairs.

If you are not a native English speaker as is my case and if you work in the software world, chances are that you had to resort to any online dictionary to find the meaning of some word. English reigns when it comes to programming languages and any other sort of computer related stuff. With Babylon the translation from/to English to a varied set of languages is just @ a click of the mouse. This amazing software product has helped me a lot since I started the computer engineering course in 2003 and I think it'll continue to play a big role in my English learning process during the years to come.

Nowadays it's practically impossible to work in the software industry without a grasp of English grammar, so that if you want to know a software product that can help you, read on.

Being a Brazilian speaking Portuguese and an avid user of Babylon since 2002 I can tell you that Babylon played and plays a big part in my English language learning. Despite having a 4.5 years course of English background, it’s always not enough. Learning is an infinite process.

Much of my contributions to ProZ comes from Babylon. At the same time I help others I learn a little bit more of English each day.
I just can’t express in words how much Babylon has helped me during these past years. At least this is an attempt.

Below is a screenshot of Babylon 8 with word auto-completion (auto-suggestion):

Babylon 8 - Main Window

When I get to a word that I don’t know yet I just select it with "Ctrl + Right Mouse Button" or copy/paste it inside Babylon’s text box to get instant translation that comes from a number of online dictionaries including Wikipedia, which is the world’s largest encyclopedia/source of information.

Babylon has its native dictionaries/glossaries but the community also develop custom ones making them free to use. Such dictionaries/glossaries are in most cases specialized ones, that is, they refer to specific fields as computer networks, software, electronics, etc. In contrast with free content, there is also premium content which you pay for.

Behind the curtains Babylon uses built-in browser functionalities as is the case of translated data returned in the form of a webpage and history navigation.

Besides translation to and from any language, full web page translation, full document translation (Word, PDF, Text), integration into Microsoft office spellers, leading dictionary packs - Oxford, Britannica, Merriam-Webster, etc, Babylon also does currency, measurements and time conversions. With that all, Babylon can be called a killer app.

I’d like to remember when exactly I started using Babylon and in which version it was, but that is a difficult task… Sometimes you get a little bit nostalgic.

Babylon has been evolving and in each new version new features get added and existing ones are refined. Version 8 in my humble opinion is fantastic!

Watch this video demo to see Babylon in action.

With Babylon there’s no more language barriers when it comes to read/written words. Take it with you and you can rest assured that you’ll have that word translated as fast as a mouse click.