Read / write to DBF files from Ruby

A little history.

I worked on a project, where a system was written in house for a period of almost 20 years and it’s done in dBase. Once cool and almighty, it’s not longer, dare we say, a system that is at the forefront of computer technology. It has numerous problems: multiple users locking tables, AD based security for each individual file/table, slow, etc.

Long story short, we decided to convert our system to a web based one, with a Debian / Nginx / Passenger / MariaDB / Ruby back-end – and whatever at the front-end. Obviously we had a problem of converting old data to mysql format, with ruby only supporting reading of dbf file via ruby dbf gem – which is great if you only need to read files.

Unfortunately, we couldn’t just abandon our system, since too much depended on it – we needed to have a slow transition – where some sections are being phased out as it’s being replaced by web based app. We needed to be able to write back to dbf files. Let me save you some time – I search long and hard, and there is no way to do it. Or so I and most of the comments on the Internet thought at the time of this writing (Jan, 09).

Until I had an epiphany – ODBC!!! I was actually reading an article about PHP, and thought about one of my first experiences – when I had to pull data from MS Access (back in ’99) into MySQL using ODBC. So below is the solution and explanation of the process. Let me tell you right now – I haven’t tried this will work on Linux. This was deployed on Win2k3 (and tested on WinXP). Please leave a comment if you got it working on Linux.

Setup a DSN for your connection.

  1. Go to Control Panel > Administrative Tools > ODBC
  2. Select System DSN tab and add a new connection
  3. Select Driver do Microsoft dBase (*.dbf) – if you are missing that – you might need to install db2k running time, that you should have if you working with dBase files.
  4. Select Version 5
  5. Give it a name – i.e. rubydbf – something unique and descriptive – this analogous to your db name in your MySQL connections
  6. Select the directory where your dbf files sit – in my case – C:\Projects\dbf
  7. Select appropriate indexes for your dbf files – either *.ndx or *.mdx files.

Lets try to access our data

Fire up shell – we are going to test our connection.

We need to make sure we have all the gems:

  gem install dbi gem install dbd-odbc

Let’s test if it worked:

require 'dbi' 
require 'odbc' 
conn = DBI.connect('DBI:ODBC:rubydbf','','')

If you didn’t get any error messages – that means that you are fine. You can try to run for a list of tables available to you through this connection.


Read data

Let me warn you right away – and I think it’s a dBase driver issue ( there are a couple of other driver’s I haven’t tried, that might be better) – some of the standard DBI ODBC commands just don’t work. I’ll give the list of the ones I found working and most useful at the end of the post.

rs = conn.select_all('select * from product')

This spits back all the data sitting in the product table, rs being your reqular ruby array. So you can do all the nice things such as rs.size or rs[3], etc. Obviously you are limited by your RAM and pc – but most modern pc’s should handle your older dbf files. The reason I’m saying this is that I found most sql statement unexecutable – for example select * from product limit 2 – won’t work.

Of course you can use things like select_many() – but I think it’s just easier to do all of your magic in ruby, simply because ruby is going to be faster and easier in this case, thou I don’t not advocate that in general – DBs are good at manipulating data – leave it to them.

Another way to query your data it is to use DBI’s prepare and execute statements:

q = conn.prepare('select * from product where partid = 14')
rs = q.fetch_all()

This approach lets you use band variables – which might be useful – if you are not just converting data, but need to pull dynamic result sets – i.e. dated reports or something.

Insert Records

Now that we can read data, let try to insert data – which is the main point of this exercise:

q = conn.prepare("insert into product (description) values('cool widget')")

If you run select statement now you should see a new record in your table. As – I said unfortunatly you can’t do limits and so on, so you can dump all you data in an array rs = conn.select_all('select * from product') and then do rs.last to see your new and shiny row

That is it. Should be enough to get you started, let me know if you run into problems – someone else mgiht think of something or sometimes

Have fun! or what amounts to it in dBase world 🙂

Если бы языки программирования были бы машинами

Below is my literary translation ( with some small changes and additions ) of a post on Mike Vanier’s website – If programming languages were cars. Translated and posted with author’s permission.

Ниже – мой литературный перевод заметки на сайте Майкла Ваниера, с небольшими добавлениями и немного отсебятины. Переведено и напечатано с разрешения автора.

  • Ada – это аццкий танк. Большой и толстый, времён 2-ой мировой, чем-то напоминает русский T-34 или американский Шерман М-4. Люди смеются над тобой когда ты им говоришь, что ты в танке. Но ты, блин, ещё посмеёшся над ними, когда наступит война, и они будут ездить на своих спортивных машинах по полю битвы. Хорошо смееётся тот, кто смеётся последний. Особенно если у него есть план, и он в танке.

  • Assembly – чисто двигатель. Машину надо построить самому, вручню подвести нефть из трубы, нефть переработать на месте, и всё это не выключая двигателя. Зато если ты аккуратен – попрёт, что твой запорожец, из анекдота, с авиационным двигателем.

  • ASP.NET – машина класса ехтра-люкс, которая хочет попасть в гараж каждего автолюбителя, как это удалось сделать главному её конкуренту. Правда ездит она только по дорогам построенным специально для неё, в случае поломки вам надо выписивать специалного механика из дорогой мастерской и запасные части, а также спойлера, диски, и трубо, стоят сумашедших денег.

  • Basic – простая машинка, для поездок в ближайший овощной магазин. Однажды популярная среди начинающих машин, была переделана крупным ПО производителем. Новая машина пригодна для поездок на более дальние расстояния, лишь издалека напоминая предыдущую модель. А-ля Toyota Corolla – 1984 и 2000.

  • C – спортивная машина, которая может ехать очень быстро, но ломается каждые 100 км.

  • Cobol – поговаривают что была такая машина, но ни один уважающий себя водитель не признается, что ездил на такой. Прячется в подвалах очень крупных гаражей. Типа инвалидки с зиловским двигателем.

  • C# – конкурентная модель симейных седанов. Однажды проехавшись на таком, вы уже не сможете пересесть на другую машину. Ваш седан просто не разрешит вам.

  • C++ – затюнингованая Си, обладает кучей всяких крутых новых кнопочек и фишечек, может проехать 500км, прежде чем поломается, но когда уж поломоается, никто не знает почему. И без-политра тут не обойдёшся.

  • dBase – это Deloarean языков програмирования. Одно время – это была самая модная тачка на районе. Так должны были виглядеть машины будушего. Когда вы садитесь за руль этой машины, вы чувствуете себя немного как тот сумашедший профессор из “Назад В Будущее”.

  • Eiffel – машина, в которую встроен инструктор по-вождению, разговаривающий с сильным французским акцентом. Он поможет вам быстро понять и исправить ваши ошибки, но не смейте прирекаться – или вас обматерят и выкинут из машины.

  • Erlang – это автопарк машин, которые едут вместе, чтобы доставить вас по месту назначения. Требуется опыт, чтобы научится управлять этим табуном, но уже если научитесь, то не не захотите учиться ездить по-другому. К тому же не важно если одна из лошадей выпадет из табуна – упряжка всё равно дотянет вас до места назначения.

  • Forth – машина которую вы собираете сами из конструктора. Она не выглядет как машина и даже не ведёт себя как ни одна другая. Зато очень эксклюзивно – ведь машина марки Forth – ездит только задом наперёд.

  • Fortran – достаточно примитивная машина, которая может ездить, только по очень прямым дорогам. Владельцы – этой машины будут до посининения доказывать вам, что это не правда, и просто у всех остальнх слишком неправильный прямой взгляд на дороги.

  • Java – это семейный вагон. Им относительно легко управлять, он не слишком быстр, но и в меру безопасен.

  • Haskell – не совсем машина. На самом деле вовсе не машина – а абстракция машина, которой вы должны описать как бы вы себя вели если бы были машиной. После чего, вам нужно будет абстракцию воплатить в реалном мире. При этом как работает прототип вы знать не имеете права. Вы так же можете сделать множество копий вашей абстрактной машины, после чего вы сможете сделать много одинкаовых поездок на этих копиях.

  • Lisp – похож на машину, но если у вас есть смекалка и лобзик, вы можете из него сделать и самолёт и атомную подводную лодки. Вы лишь ограничены своей фантазией и лобзиком. К сожелению никто вам не верит – все думают, что это всего лишь старый советский анекдот.

  • Mathematica – продукт попыток сделать из Лиспа – навигационый спутник. Может расчитать оиптимальный маршрут до места назначения, но и стоит эта машина как спутник.

  • Matlab – дешовый вариант Математики, на подобе, распечатаных карт. Очень удобна для передвижения по знакомой местности, но стоит вам попаст в чащёбу, и вы быстрее выберетесь пешком.

  • Ocaml – европейские автопроизводители постарались над её сексуальным дезайном. Она не такая быстрая как Си, но почти никогда не ломается, в отличии от своих амерканских скоростных аналогов. Правда из-за того, что делали её во Франции, приборная доска, комьютерный чип и руль находятся в совершенно неожиданных местах.

  • Perl – говорят, что это очень классная точила, но книга по эксплуатации, написана по-олбански, а логика управления – отчасти напоминает женскую. Оданко если вы научитесь управлять этой машиной, вам уже не захочется пересаживаться на другю.

  • PHP – это как Экарус. В него набито куча народу, в него иногда не заедешь легко в маленкий дворик, но всем хочется такой поводить и желательно оранжего цвета.

  • Prolog – делает за вас всё автоматически, после того как вы дадите эй инструкции – но усилий которые вам на это потребуются, с лихвой хватило бы чтобы уже сбегать туда и обратно два раза.

  • Python – это замечательная машина для начинающих. Если вы никогда не поедете на болото, не заберётесь на вершину вулкана или не полетите в космос, другое средство передвижения вам и не потрбуется.

  • Ruby – машина, которя пострил один японский автостроитель в подсобке, из останков того что осталось после аварии между Пёрлом, Питоном и Смолтоком. Правда некоторые водители жалуются: ” На хера в машине три руля?”, но не задумиваются они над тем, что первый руль может отказать, а второй просто не захочет с вами разговаривать. Правда поговоривают , что её скоро перестроют с одним рулём, но с 6-ю колёсами для увеличения проходимости и скорости.

  • Smalltalk – очень маленкая машина, придуманая для начинаюших водителей и конструкторов. Она не быстра, но зато вы можете сделать из неё трех-колёсный мопед или веложабу. Единстевенное маааааленкое отличие: вы ей не управляете, вы посилаете смс-ки что бы она сделала, то что вы хотите.

  • Visual Basic – машина которая ездит на вас!