cmiles – blog

Charles Miles – Tucson Hiking, Outside and Adventures, Excel, .net, Life

Moving Excel data into .net

This past week I have revisited some of the different techniques for moving Excel data into a .net datatable in an effort to improve the speed/reliability of my code. In a perfect world Excel would only be a destination for data, I think there is a certain amount of futility in using Excel as a data source – but in practice Excel often seems like the only available option to collect a wide variety of data (reports to Excel seem common – end-user direct database access on the other hand…).
This post does not contain any information that cannot be found in other articles/posts/blogs, but I thought an overview with links might be useful.

The most useful list I have ever seen of links relevant to this topic:
http://blogs.msdn.com/pranavwagh/articles/excel_ado.aspx

The title of the post is ‘USING ADO AND ADO.NET WITH EXCEL: Resources and Known Issues’ (it also covers automation and general excel information).

Methods-Notes-Ideas

Jet/ADO.NET

There are many examples online using Jet (I think the two links below give enough examples for a good overview). Jet is fast and can query saved/closed files. If your data is very consistent (no values in a single column that Jet will confuse the type of) and you are interested in saved files (rather than information in a running instance of Excel) this may be a good choice – it certainly seems to retrieve data quite quickly.

The chance that Jet will incorrectly identify the data type of a column and introduce errors into the data (esp. in situations where the exact data is unpredictable (dynamic!)) makes me reluctant to use this solution. Also, this style solution may be a poor choice for the end user if you want to import what they see on screen (the file on-screen must be saved before changes can be read, it does not seem like a good user-interface choice to me (and automation of saving the file seems problematic/dangerous)). These links have good information:
http://blog.lab49.com/?p=196
http://support.microsoft.com/?scid=kb;en-us;316934&spid=1249&sid=global

Range.Value/Arrays

Excel can return a range of values as a 2-dimensional Object array. This method is fairly fast (although maybe not seem quite as fast as Jet), and the values are far more predictable (in my opinion). This solution is interesting when you want to extract the information a user is seeing on-screen. For the most part this solution is direct and simple (although beware confusing differences formatting can cause between .value and displayed value).
I like this solution and have been using it frequently. For small sets of cells it may be just as effective to loop through each cell in the range and retrieve the range.value – this is even slower (and less reliable see: http://support.microsoft.com/kb/216400/) – but may allow you to bypass the Object array and go directly into your DataTable or list. This link has code examples:
http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q302094

Taking Information from the Clipboard

M.B. mentioned this solution to me before I saw an online code example. This is a simple idea, copy the data to the clipboard in Excel and then pull it off the clipboard in .net. This is an interesting solution, the .net application does not need an Excel reference (no version conflicts and pias!) and you could write your program to take information from a wide variety of programs. I like the user-interface options – most users are comfortable with copy/paste . The link below will get you started:

http://www.codeguru.com/vb/controls/vbnet_controls/datagridcontrol/article.php/c6393/

The problems I have had with this technique are related to the choice of formats available on the clipboard. Csv seems to be the best choice (other opinions?), which means that commas in your data will be a problem. Replacing commas in Excel with a substitute string (and then reversing the replace in .net) is a possibility, but it detracts from the simplicity of the solution.
I think that cell formats can be more problematic here than in the range.value methods (maybe my prejudice from seeing monetary values so often – the copy to clipboard will can pick up the dollar sign, very likely not what you want – although likely a pretty safe string manipulation to remove…)

Here is the code that I use to go from an excel range (tableRange in the example – which is declared at the class level in my code) to a streamreader (for use in .net) via the clipboard.


  Public Function WftToStreamreaderViaClipboardCsv( _
    ByVal commaSubstituteString As String) _
    As StreamReader
 
    'Because the .Find inherits the current settings I set everything each time.
    'Later I will transform the stream with:
    '
    '  Dim commaSepChar As Char = ","c
    '  splitArray = rowFromStream.Split(commaSepChar)
    '
    '  For loopElements As Integer = 0 To ColumnCount - 1
    '    splitArray(loopElements) = _
    '      splitArray(loopElements).Replace(commaSubstituteString, ",")
    '  Next
    '
    'Because of the coding choice I throw an exception if the range contains the
    'comma substitution string even if commas are not present in the data.
 
    Dim foundPreExistingSubstitutionString As Excel.Range = _
      _tableRange.Find(What:=commaSubstituteString, _
        After:=_tableRange.Cells(1, 1), _
        LookIn:=Excel.XlFindLookIn.xlValues, _
        LookAt:=Excel.XlLookAt.xlPart, _
        SearchOrder:=Excel.XlSearchOrder.xlByRows, _
        SearchDirection:=Excel.XlSearchDirection.xlNext, _
        MatchCase:=False)
 
    If foundPreExistingSubstitutionString IsNot Nothing Then
      Throw New ArgumentException("The Comma Substitution String" _
        & "is found in the original text and are not valid.")
      Return Nothing
    End If
 
    Dim rangeWithCommas As Excel.Range = _tableRange.Find(What:=",", _
        After:=_tableRange.Cells(1, 1), _
        LookIn:=Excel.XlFindLookIn.xlValues, _
        LookAt:=Excel.XlLookAt.xlPart, _
        SearchOrder:=Excel.XlSearchOrder.xlByRows, _
        SearchDirection:=Excel.XlSearchDirection.xlNext, _
        MatchCase:=False)
 
    Dim reverseCommaSubstitutionNeeded As Boolean = False
 
    Do While rangeWithCommas IsNot Nothing
      'Although the find should be limited to finding xlValues this is
      'a x2 that a formula is not being modified. The Try...Catch block
      'is cautious but better than false results.
 
      If CType(rangeWithCommas.HasFormula, Boolean) = False Then
        Dim stringToModify As String = ""
        Try
          stringToModify = CType(rangeWithCommas.Value, String)
        Catch ex As Exception
          Throw
        End Try
 
        rangeWithCommas.Value = stringToModify.Replace(",", _
          commaSubstituteString)
        reverseCommaSubstitutionNeeded = True
      End If
 
      rangeWithCommas = _tableRange.Find(What:=",", After:=rangeWithCommas, _
        LookIn:=Excel.XlFindLookIn.xlValues, LookAt:=Excel.XlLookAt.xlPart, _
        SearchOrder:=Excel.XlSearchOrder.xlByRows, _
        SearchDirection:=Excel.XlSearchDirection.xlNext, _
        MatchCase:=False)
 
    Loop
 
    _tableRange.Copy()
 
    If Clipboard.ContainsData(DataFormats.CommaSeparatedValue) = False Then
      Return Nothing
    End If
 
    Dim streamFromClipboard As New StreamReader _
        (CType(Clipboard.GetData(DataFormats.CommaSeparatedValue), Stream))
 
    If reverseCommaSubstitutionNeeded Then
      'Returns the Excel values to their original with comma values
 
      rangeWithCommas = _tableRange.Find(_tableRange.Find( _
        What:=commaSubstituteString, _
        After:=_tableRange.Cells(1, 1), _
        LookIn:=Excel.XlFindLookIn.xlValues, _
        LookAt:=Excel.XlLookAt.xlPart, _
        SearchOrder:=Excel.XlSearchOrder.xlByRows, _
        SearchDirection:=Excel.XlSearchDirection.xlNext, _
        MatchCase:=False))
 
      Do While rangeWithCommas IsNot Nothing
        If CType(rangeWithCommas.HasFormula, Boolean) = False Then
          Dim stringToModify As String = ""
          Try
            stringToModify = CType(rangeWithCommas.Value, String)
          Catch ex As Exception
            Throw
          End Try
          rangeWithCommas.Value = _
            stringToModify.Replace(commaSubstituteString, ",")
        End If
 
        rangeWithCommas = _tableRange.Find(What:=commaSubstituteString, _
        After:=rangeWithCommas, _
        LookIn:=Excel.XlFindLookIn.xlValues, _
        LookAt:=Excel.XlLookAt.xlPart, _
        SearchOrder:=Excel.XlSearchOrder.xlByRows, _
        SearchDirection:=Excel.XlSearchDirection.xlNext, _
        MatchCase:=False)
      Loop
 
    End If
 
    Return streamFromClipboard
 
  End Function

Other Options

I am not familiar with VSTO but I believe that the databinding of named ranges might be worth looking into if you/your target machines are all running Excel 2003(+) and the cost of VSTO is not an issue.

Save as – Excel has a number of save as options (such as tab-delimited) that can be useful to work with.

XML – XML is becoming more important in Office – there may be some possibilities here although I would guess solutions are going to be pretty specific to various office versions for the time being.

DTS/Sql Server – this steps out a little from .net DataTables and overlap with the Jet discussion but may be options also depending on the project.

All comments welcome,

CM

Filed under: .net, Excel

2 Responses

  1. Alison Taylor says:

    Awesome site CAM! You are indeed an Excel guru. If only I could retain or absorb so much information….maybe someday:) Love ya!

  2. esif44 says:

    I thought it was going to be some boring old publish, but it really compensated for my time. I will post a link to this page on my blog. I’m sure my visitors will come across that extremely useful
    Traffic Scorpion

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

twitter -> twitterings

  • Just saw the new Resharper 6.1 Early Access version has Async CTP support listed - downloading now... 6 months ago
  • Quick post about FeedDemon/Pinboard/Save to Pinboard on Android as my choice for Google Reader Sharing cmiles.info/2011/11/05/goo… 6 months ago
  • FeedDemon+Custom Sharing XML->Pinboard; NewsRob + Save to Pinboard on Android - replacing Google Reader sharing, Reader now just for sync... 7 months ago
  • Doing a few Max - cycling74.com - tutorials - what fun, first time in a decade I have played with this... 7 months ago

RSS pinboard -> links

  • Gmap4 - Share Enhanced Google Maps
    A very cool tool - free for non-commercial use - that can produce very nice (and very usable) topo maps that can have data (GPX, KML,...) overlaid on it very easily!
  • Vistoso Hiking Club Hikes Database
    Short descriptions of hikes near Tucson with a few off trail and interesting destinations - no doubt there are more informative sources but sometimes the simplest thing is nice...
  • Bill Hill - Pictures
    I don't stumble on that many well organized great sets of Tucson hiking photos so saving this link!
  • [WPF] How to bind to data when the DataContext is not inherited
    This solved a problem for me with control of DataGrid Column visibility via Data Binding. Did not test/research/profile this extensively, but for my problem this worked like a charm.

RSS cmiles-consuming -> posts

  • Kafka on the Shore and The Wind-Up Bird Chronicle, Haruki Murakami 2012 June 1
    Kafka on the Shore and The Wind-Up Bird Chronicle by Haruki Murakami are favorites of mine. To combine them into one blog post seems slightly odd – they are not part of a series and are complex enough that reducing them down to a few sentences seems like a disservice. But what these have in [...]
  • Hyperion and The Fall of Hyperion, Dan Simmons 2012 May 16
    I first read Dan Simmons‘s Hyperion in the early 1990s – the Hyperion Cantos is quite famous and I would occasionally see Hyperion listed in Amazon recommendations and ‘top’ lists (see the ISFDB Top 100 Lists and Your Picks: Top 100 Science-Fiction, Fantasy Books from npr books (note that you may get some amusement out [...]
  • Wool Omnibus (Wool 1-5), Hugh Howey 2012 May 1
    I don’t usually pay much attention to Amazon’s recommendations – but after finishing 1Q84 I wanted something new and, for whatever reason, the Wool Omnibus by Hugh Howey jumped out at me on Amazon’s list. Wool takes place in a bleak future where the characters live in self sufficient underground silos with only a vague [...]
  • 1Q84, Haruki Murakami 2012 April 15
    I am a fan of Haruki Murakami, so I was excited when the English version of 1Q84 became available. I picked up and put down this book several times while reading it and I have to admit that I just really don’t know what to say about it – Long/Interesting/What?/I am glad I read it/Why?/1984/hmmm… [...]
  • Ride the Divide 2012 April 2
    Ride the Divide has great scenery, interesting people, injuries, struggles and riding along the Great Divide Mountain Bike Route that goes from Banff, Canada to the Mexican border! While I am familiar with some of the long distance hiking trails in the US I had no idea this route existed and it was fascinating to [...]
  • Forks over Knives 2012 March 20
    Forks over Knives (official website), directed by Lee Fulkerson, is a rather long documentary with the singular message that plant based diets are better than meat based diets (it may be slightly more subtle than that, but I think that is a pretty fair summary). I watched the film days after seeing Tabloid and could [...]
  • Tabloid, The Thin Blue Line 2012 March 15
    Tabloid – by Errol Morris – is the story of Joyce McKinney. McKinney was involved in a widely publicized case/scandal/incident in England in the late 1970s sometimes given the colorful name ‘The Case of the Manacled Mormon’. I had no knowledge of the events prior to the film – which might have added to the [...]
  • Jig 2012 March 1
    Jig follows a number of dancers leading up to their participation in the 40th Irish Dancing World Championships (2010). This film is a friendly, short and entertaining glimpse into a world that I did not know even existed – great fun. Simple, good! Rating: 4 of 5 First Watch Date: December 2011 CM
  • 180° South: Conquerors of the Useless 2012 February 16
    180° South: Conquerors of the Useless (official site) direct by Chris Malloy follows the journey of Jeff Johnson from Ventura, California to the Corcovado Volcano in Patagonia. The film has some amazing footage of Patagonia and interesting people (including Yvon Chouinard and Douglas Tompkins) – but, somehow, it didn’t hold my interest… Too […]
  • Beats, Rhymes & Life: The Travels of a Tribe Called Quest 2012 January 30
    I have no idea when I first heard a Tribe Called Quest (official site) – but it was the early 2000s before I really ‘found’ them and started listening. I would not call myself a devotee – casual fan is probably the best description – but even as a casual fan I was excited when [...]
email: charles@cmiles.info

flickr -> pictures

1205 Looking down Pontatoc Canyon

1205 Looking up canyon from the end of the Pontatoc Canyon Trail

1205 Pontatoc Canyon End of Trail Sign

1205 Looking up at the rocks above the end of the Pontatoc Canyon Trail

1205 Catepillar

1205 Maybe from the fire fighting

1205 Looking back up Sabino Canyon from Brinkley Point

1205 View towards Sabino Canyon from Brinkley Point

1205 Charles and Alison

1205 View from Brinkley Point

More Photos
Follow

Get every new post delivered to your Inbox.